JavaScript Editor Javascript validator     Javascripts

Main Page


Previous Section Next Section

5.11 Calendar

The ASP Calendar control is a rich web control that provides several capabilities:

  • Displays a calendar showing a single month

  • Allows the user to select a day, week, or month

  • Allows the user to select a range of days

  • Allows the user to move to the next or previous month

  • Allows all aspects of the appearance of the calendar to be customized either at design time or under program control

  • Programmatically controls the display of specific days

The Calendar control is extremely customizable, with a large variety of properties and events. Before digging into all the detail, look at a bare bones .aspx file showing a simple Calendar control, along with the resulting web page. Example 5-38 contains the code, and Figure 5-20 shows the results. Since there is no script block in this code, there is no need for equivalent C# and VB.NET versions.

Example 5-38. Simple Calendar control, Calendar-Simple.aspx
<html>
   <body>
   <form runat="server">

      <h1>ASP Controls</h1>
      <h2>Calendar Demonstration</h2>

      <asp:Calendar
         id="cal"
         runat="server" >
      </asp:Calendar>
   </form>
   </body>
</html>
Figure 5-20. A simple Calendar control
figs/pan2_0520.gif

Pretty spiffy. Very few lines of code yield a web page with a working calendar that displays the current month. The user can select a single day (although at this point nothing happens when a day is selected, other than it being highlighted) and move through the months by clicking on the = and = navigation symbols on either side of the month name.

In addition to the properties inherited by all the ASP controls that derive from WebControl, the Calendar has many properties of its own, which are listed in Table 5-22.

Table 5-22. Properties of the Calendar control

Name

Type

Get

Set

Values

Description

CellPadding

Integer

x

x

0, 1, 2, and so on

Distance in pixels between the border and contents of a cell. Applies to all the cells in the calendar and to all four sides of each cell. Default is 2.

CellSpacing

Integer

x

x

0, 1, 2, and so on

Distance in pixels between cells. Applies to all the cells in the calendar. Default is 0.

DayNameFormat

DayNameFormat

x

x

Full, Short, FirstLetter, FirstTwoLetters

Format of days of the week. Values are self-explanatory, except Short, which is first three letters. Default is Short.

FirstDayOfWeek

FirstDayOfWeek

x

x

Default, Sunday, Monday, . . . Saturday

Day of week to display in first column. Default (the default) specifies system setting.

NextMonthText

String

x

x

 

Text for next month navigation control. The default is &gt, which renders as the greater than sign (>). Only applies if ShowNextPrevMonth property is true.

NextPrevFormat

NextPrevFormat

x

x

CustomText, FullMonth, ShortMonth

To use CustomText, set this property and specify the actual text to use in NextMonthText and PrevMonthText.

PrevMonthText

String

x

x

 

Text for previous month navigation control. Default is "&lt;, which renders as less than sign (<). Only applies if ShowNextPrevMonth property is true.

SelectedDate

DateTime

x

x

 

A single selected date. Only the Date is stored; the time is set to null (nothing in VB.NET).

SelectedDates

DateTime

x

x

DateTime

Collection of DateTime objects when multiple dates selected. Only the Date is stored; the time is set to null (Nothing in VB.NET).

SelectionMode

CalendarSelectionMode

x

x

 

Described later in this section.

SelectMonthText

String

x

x

 

Text for month selection element in the selector column. Default is "&gt;&gt;, which renders as two greater than signs (>). Only applies if SelectionMode set to DayWeekMonth.

ShowDayHeader

Boolean

x

x

true, false

Indicates if days of week heading shown. Default is true.

ShowGridLines

Boolean

x

x

true, false

Indicates if grid lines between cells shown. Default is false.

ShowNextPrevMonth

Boolean

x

x

true, false

Indicates if next and previous month navigation elements are shown. Default is true

ShowTitle

Boolean

x

x

true, false

Indicates if title is shown. If false, then next and previous month navigation elements also hidden. Default is true

TitleFormat

TitleFormat

x

x

Month, MonthYear

Indicates whether title is month only or month and year. Default is MonthYear.

TodaysDate

DateTime

x

x

 

Today's date.

VisibleDate

DateTime

x

x

 

Any date in the month to display.

If you want to give the user the ability to select either a single day, an entire week, or an entire month, then you must set the SelectionMode property. Table 5-23 lists the legal values for the SelectionMode property.

Table 5-23. Members of the CalndarSelectionMode property enumeration

SelectionMode

Description

Day

Allows the user to select a single day. This is the default value.

DayWeek

Allows user to select either a single day or an entire week.

DayWeekMonth

Allows user to select either a single day, an entire week, or an entire month.

None

Nothing on the Calendar can be selected.

Example 5-39 modifies the code in Example 5-38 to add the SelectionMode property. The resulting Calendar, with the entire month selected, looks like Figure 5-21.

Example 5-39. Simple Calendar control with SelectionMode property, Calendar-Simple2.aspx
<html>
   <body>
   <form runat="server">

      <h1>ASP Controls</h1>
      <h2>Calendar Demonstration</h2>
      <h3>Selection Property</h3>

      <asp:Calendar
         id="cal"
         SelectionMode="DayWeekMonth"
         runat="server" />
   </form>
   </body>
</html>

When the SelectionMode property is set to DayWeek, an extra column containing the = symbol is added to the left side of the calendar. Clicking on one of those symbols selects that entire week.

Figure 5-21. Calendar with month selected
figs/pan2_0521.gif

Similarly, when the SelectionMode property is set to DayWeekMonth, in addition to the week selection column, a = = symbol is added to the left of the day names row. Clicking on that symbol selects the entire month, as is shown in Figure 5-21.

There are a number of properties that control the style for each part of the calendar. These properties are listed in Table 5-24 and demonstrated in Example 5-40.

Table 5-24. Calendar control style properties

Name

Description

DayHeaderStyle

Specifies the style for the days of the week

DayStyle

Specifies the style for the dates

NextPrevStyle

Specifies the style for the month navigation controls

OtherMonthDayStyle

Specifies the style for the dates not in the currently displayed month

SelectedDayStyle

Specifies the style for the selected dates

SelectorStyle

Specifies the style for the week and month selection column

TitleStyle

Specifies the style for the title section

TodayDayStyle

Specifies the style for today's date

WeekendDayStyle

Specifies the style for the weekend dates

Note that there are two different syntaxes for using these style properties. The first puts the style attribute inside the Calendar control tags, using the convention of hyphenating the style name and property, as in the following:

DayHeaderStyle-BackColor="Black"

The second syntax, used for most of the style examples here, encloses each style within its own HTML tag, rather than including it with other properties within the asp:Calendar tag:

<DayStyle
   BackColor="White"
   ForeColor="Black"
   Font-Name="Arial" />

The properties listed in Table 5-24 derive many of their subproperties from the Style class. Those properties have all been described elsewhere in this chapter and are mostly self-explanatory. These include:

  • BackColor

  • BorderColor

  • BorderStyle

  • BorderWidth

  • CssClass

  • Font

  • ForeColor

  • Height

  • HorizontalAlign

  • VerticalAlign

  • Width

  • Wrap

In addition, there are four Boolean properties that control various aspects of the calendar. They are shown in Table 5-25.

Table 5-25. Boolean properties controlling various aspects of the Calendar control's appearance

Property

Default

Description

ShowDayHeader

true

Controls visibility of the names of the days of the week

ShowGridLines

false

Controls visibility of the grid lines between the days of the month

ShowNextPrevMonth

true

Controls visibility of the month navigation controls

ShowTitle

true

Controls visibility of the title section

Example 5-40 shows a basic calendar control with many of the Style properties set. The resulting calendar is shown in Figure 5-22.

Example 5-40. Calendar control with Styles, Calendar-Simple3.aspx
<html>
   <body>
   <form runat="server">

      <h1>ASP Controls</h1>
      <h2>Calendar Demonstration</h2>
      <h3>Styles</h3>

      <asp:Calendar
         id="cal"
         SelectionMode="DayWeekMonth"
         ShowGridLines="true"
         ShowNextprevMonth="true"
         CellPadding="7"
         CellSpacing="5"
         DayNameFormat="FirstTwoLetters"
         FirstDayOfWeek="Monday"
         NextPrevFormat="CustomText"
         NextMonthText="Next >"
         PrevMonthText="< Prev"
         DayHeaderStyle-BackColor="Black"
         DayHeaderStyle-ForeColor="White"
         DayHeaderStyle-Font-Name="Arial Black"
         runat="server" >

         <DayStyle
            BackColor="White"
            ForeColor="Black"
            Font-Name="Arial" />
         <NextPrevStyle
            BackColor="DarkGray"
            ForeColor="Yellow"
            Font-Name="Arial" />
         <OtherMonthDayStyle
            BackColor="LightGray"
            ForeColor="White"
            Font-Name="Arial" />
         <SelectedDayStyle
            BackColor="CornSilk"
            ForeColor="Blue"
            Font-Name="Arial" 
            Font-Bold="true"
            Font-Italic="true"/>
         <SelectorStyle
            BackColor="CornSilk"
            ForeColor="Red"
            Font-Name="Arial" />
         <TitleStyle
            BackColor="Gray"
            ForeColor="White"
            HorizontalAlign="Left"
            Font-Name="Arial Black" />
         <TodayDayStyle
            BackColor="CornSilk"
            ForeColor="Green"
            Font-Name="Arial" 
            Font-Bold="true"
            Font-Italic="false">
         </TodayDayStyle>
         <WeekendDayStyle
            BackColor="LavenderBlush"
            ForeColor="Purple"
            Font-Name="Arial" 
            Font-Bold="false"
            Font-Italic="false"/>
      </asp:Calendar>
   </form>
   </body>
</html>
Figure 5-22. Calendar with Styles
figs/pan2_0522.gif

In the code in Example 5-40, notice that the DayHeaderStyles are contained within the Calendar tag, while all the other styles use their own tag. This is strictly a matter of personal preference. Notice also that the TodayDayStyle uses a separate closing tag, while all the other styles are self-closing. This too is a matter of personal preference.

5.11.1 Programming the Calendar Control

The ASP Calendar control provides three events and one method that are not inherited from other control classes and are of particular interest. By providing event handlers for the events, you can exercise considerable control over how the calendar behaves. These are:

SelectionChanged event
DayRender event
VisibleMonthChanged event
SelectRange method

The following sections describe each of these in detail.

5.11.1.1 SelectionChanged event

The SelectionChanged event fires when the user makes a selection—either a day, a week, or an entire month—in the Calendar control. The event is not fired if the selection is changed programmatically. The event handler is passed an argument of type EventArgs.

Example 5-41 demonstrates handling the SelectionChanged event in C#, and Example 5-42 demonstrates the same thing in VB.NET. (The VB.NET example, however, includes only the script block, since its HTML is identical to that in Example 5-41.) Whenever you select a new date, it displays text strings with today's date, the selected date, and number of days selected.

Example 5-41. Calendar control with SelectionChanged event in C#, csASPCalendarSelectionChanged.aspx
<%@ Page Language="C#" %>
<script  runat="server">
   void SelectionChanged(Object sender, EventArgs e)
   {
      lblTodaysDate.Text = "Today's Date is " +  
            cal.TodaysDate.ToShortDateString(  );

      if (cal.SelectedDate != DateTime.MinValue)
         lblSelected.Text = "The date selected is " + 
               cal.SelectedDate.ToShortDateString(  );
      lblCountUpdate(  );
   }

   void lblCountUpdate(  )
   {
      lblCount.Text = "Count of Days Selected:  " + 
            cal.SelectedDates.Count.ToString(  );
   }
</script>

<html>
   <body>
   <form runat="server">

      <h1>ASP Controls</h1>
      <h2>Calendar Control</h2>
      <h2>SelectionChanged Event</h2>

      <asp:Calendar
         id="cal"
         SelectionMode="DayWeekMonth"
         ShowGridLines="true"
         ShowNextprevMonth="true"
         CellPadding="7"
         CellSpacing="5"
         DayNameFormat="FirstTwoLetters"
         FirstDayOfWeek="Monday"
         NextPrevFormat="CustomText"
         NextMonthText="Next &gt;"
         PrevMonthText="&lt; Prev"
         onSelectionChanged="SelectionChanged"
         DayHeaderStyle-BackColor="Black"
         DayHeaderStyle-ForeColor="White"
         DayHeaderStyle-Font-Name="Arial Black"
         runat="server" >

         <DayStyle
            BackColor="White"
            ForeColor="Black"
            Font-Name="Arial" />
         <NextPrevStyle
            BackColor="DarkGray"
            ForeColor="Yellow"
            Font-Name="Arial" />
         <OtherMonthDayStyle
            BackColor="LightGray"
            ForeColor="White"
            Font-Name="Arial" />
         <SelectedDayStyle
            BackColor="CornSilk"
            ForeColor="Blue"
            Font-Name="Arial" 
            Font-Bold="true"
            Font-Italic="true"/>
         <SelectorStyle
            BackColor="CornSilk"
            ForeColor="Red"
            Font-Name="Arial" />
         <TitleStyle
            BackColor="Gray"
            ForeColor="White"
            HorizontalAlign="Left"
            Font-Name="Arial Black" />
         <TodayDayStyle
            BackColor="CornSilk"
            ForeColor="Green"
            Font-Name="Arial" 
            Font-Bold="true"
            Font-Italic="false"/>
         <WeekendDayStyle
            BackColor="LavenderBlush"
            ForeColor="Purple"
            Font-Name="Arial" 
            Font-Bold="false"
            Font-Italic="false"/>
      </asp:Calendar>

      <br/>
      <asp:Label id="lblCount" runat="server" />
      <br/>
      <asp:Label id="lblTodaysDate" runat="server" />
      <br/>
      <asp:Label id="lblSelected" runat="server" />
   </form>
   </body>
</html>
Example 5-42. Calendar control with SelectionChanged event script block in VB.NET, vbASPCalendarSelectionChanged.aspx
<%@ Page Language="VB"%>
<script  runat="server">
   sub SelectionChanged(ByVal Sender as Object, _
                        ByVal e as EventArgs)
      lblTodaysDate.Text = "Today's Date is " & _
            cal.TodaysDate.ToShortDateString(  )

      if (cal.SelectedDate <> DateTime.MinValue) then
         lblSelected.Text = "The date selected is " & _
               cal.SelectedDate.ToShortDateString(  )
      end if

      lblCountUpdate(  )
   end sub

   sub lblCountUpdate(  )
      lblCount.Text = "Count of Days Selected:  " & _
            cal.SelectedDates.Count.ToString(  )
   end sub
</script>

Skipping over the script block at the beginning of Example 5-41 for a moment, you can see that this example adds the onSelectionChanged event handler to the Calendar control. This event handler points to the SelectionChanged method in the script block. Three ASP Label controls are also added after the Calendar control. The first of these labels, named lblCount, is used to display the number of days selected. The other two labels, named lblTodaysDate and lblSelected, are used to display today's date and the currently selected date, respectively.

All three of these labels have their Text property set in the SelectionChanged event handler method. Looking at that method in either Example 5-41 or Example 5-42, you can see that the label containing today's date is filled by getting the Calendar control's TodaysDate property. In C#, this is done using code similar to:

lblTodaysDate.Text = "Today's Date is " +  
      cal.TodaysDate.ToShortDateString(  );

In VB.NET, the code looks like:

lblTodaysDate.Text = "Today's Date is " & _
      cal.TodaysDate.ToShortDateString(  )

The id of the Calendar control is cal. TodaysDate is a property of the Calendar control that returns an object of type System.DateTime. To assign this to a Text property (which is an object of type String), you must convert the DateTime to a String. This is done with the ToShortDateString method. The DateTime object has a variety of methods for converting a DateTime object to other formats, including those shown in Table 5-26.

Table 5-26. Methods for converting a DateTime object to a string

Method name

Description

ToFileTime

Converts to the format of the local filesystem

ToLongDateString

Converts to a long date string

ToLongTimeString

Converts to a long time string

ToShortTimeString

Converts to a short time string

ToString

Converts to a string

Although not specific to ASP.NET, the DateTime class is very useful for obtaining all sorts of date and time information. Some of the read-only properties available from this class include those listed in Table 5-27.

Table 5-27. DateTime read-only properties

Property name

Description

Date

Returns the date component

Day

Returns the day of the month

DayOfWeek

Returns the day of the week

DayOfYear

Returns the day of the year

Hour

Returns the hour component

Millisecond

Returns the millisecond component

Minute

Returns the minute component

Month

Returns the month component

Second

Returns the second component

Ticks

Returns the number of 100 nanosecond ticks representing the date and time

TimeOfDay

Returns the time of day

Year

Returns the year component

To detect if any date has been selected, you test to see if the currently selected date, cal.SelectedDate, is equal to DateTime.MinValue. DateTime.MinValue is a constant representing the smallest possible value of DateTime and is the default value for the SelectedDate property if nothing has been selected yet. MinValue has the literal value of 12:00:00 AM, 1/1/0001 CE. There is also a MaxValue that has the literal value of 11:59:59 PM, 12/31/9999 CE.

CE, which stands for the Common Era, is the scientific notation for the span of years referred to as AD (Anno Domini) on the Gregorian calendar. BCE (Before Common Era) is the scientific equivalent to BC (Before Christ).

If a date has been selected by the user, the Text property of the Label control is set to the string value of the SelectedDate property. In both C# and VB.NET, the code that accomplishes this is the same (except for the semicolon in C#):

cal.SelectedDate.ToShortDateString(  )

The lblCount label displays the number of days selected. The SelectionChanged event procedure calls the lblCountUpdate method, which sets the Text property of the lblCount Label control. To set that control, you must determine how many dates were selected. The Calendar control has a SelectedDates property that returns a SelectedDates collection. SelectedDates is a collection of DateTime objects representing all the dates selected in the Calendar control. Count is a property of the SelectedDatesCollection object that returns an integer containing the number of dates in the collection. Since the Count property is an integer, you must use the ToString method to convert it to a string so that it can be assigned to the Text property. Once again, the code to do this in C# and in VB.NET is identical (although in VB.NET the call to the ToString method is optional):

cal.SelectedDates.Count.ToString(  )

Although SelectedDates (the collection of selected dates) and SelectedDate (the single selected date) both contain DateTime objects, only the Date value is stored. The time value for these objects is set to a null reference in C# and to Nothing in VB.NET.

The range of dates in the SelectedDates collection is sorted in ascending order by date. When the SelectedDates collection is updated, the SelectedDate property is automatically updated to contain the first object in the SelectedDates collection.

The result of the ASP.NET pages in Example 5-41 and Example 5-42 is shown in Figure 5-23.

Figure 5-23. Calendar with a SelectedDate
figs/pan2_0523.gif

The user can navigate from month to month by clicking on the month navigation controls to either side of the month title. The user can also select a single day by clicking on that day, or an entire week by clicking on the week selector control, or the entire month by clicking on the month selector control. However, you can give the user much more flexibility than this. To demonstrate, you will add several controls and methods.

To enable the user to navigate directly to any month in the current year, add a DropDownList containing all the months of the year. You also add a button, labeled TGIF, which selects all the Fridays in the currently viewed month. The code for these two additions is shown in Example 5-43 in C# and Example 5-44 in VB.NET. The VB.NET version shows code only; its HTML content is the same as in Example 5-43. Lines that have been added are shown in boldface.

Example 5-43. Calendar control with additional selection functionality in C#, csASPCalendarMoreSelections.aspx
<%@ Page Language="C#" %>
<script  runat="server">
   //  This Page_Load makes the selected days visible first time
   //  the TGIF button is clicked by initializing the VisibleDate
   //  property.
   void Page_Load(Object sender, EventArgs e)
   {
      if (!IsPostBack)
     {
        cal.VisibleDate = cal.TodaysDate;
        ddl.SelectedIndex = cal.VisibleDate.Month - 1;
      }
      lblTodaysDate.Text = "Today's Date is " +  
            cal.TodaysDate.ToShortDateString(  );
   }

   void SelectionChanged(Object sender, EventArgs e)
   {
      lblSelectedUpdate(  );
      lblCountUpdate(  );
   }

   void ddl_SelectedIndexChanged(Object sender, EventArgs e)
   {
      cal.SelectedDates.Clear(  );
      lblSelectedUpdate(  );
      lblCountUpdate(  );
      cal.VisibleDate = new DateTime(cal.VisibleDate.Year, 
                        Int32.Parse(ddl.SelectedItem.Value), 1);
   }

   void btnTgif_Click(Object sender, EventArgs e)
   {
      int currentMonth = cal.VisibleDate.Month;
      int currentYear = cal.VisibleDate.Year;

      cal.SelectedDates.Clear(  );

      for (int i = 1; 
               i <= System.DateTime.DaysInMonth(currentYear, 
                                                currentMonth); 
               i++ )
      {
         DateTime date = new DateTime(currentYear, currentMonth, i);
         if (date.DayOfWeek == DayOfWeek.Friday)
            cal.SelectedDates.Add(date);
      }

      lblSelectedUpdate(  );
      lblCountUpdate(  );
   }

   void lblCountUpdate(  )
   {
      lblCount.Text = "Count of Days Selected:  " + 
            cal.SelectedDates.Count.ToString(  );
   }

   void lblSelectedUpdate(  )
   {
      if (cal.SelectedDate != DateTime.MinValue)
         lblSelected.Text = "The date selected is " + 
               cal.SelectedDate.ToShortDateString(  );
      else
        lblSelected.Text = "";
   }
</script>

<html>
   <body>
   <form runat="server">

      <h1>ASP Controls</h1>
      <h2>Calendar Control</h2>
      <h2>More Selections</h2>

      <asp:Calendar
         id="cal"
         SelectionMode="DayWeekMonth"
         ShowGridLines="true"
         ShowNextprevMonth="true"
         CellPadding="7"
         CellSpacing="5"
         DayNameFormat="FirstTwoLetters"
         FirstDayOfWeek="Monday"
         NextPrevFormat="CustomText"
         NextMonthText="Next &gt;"
         PrevMonthText="&lt; Prev"
         onSelectionChanged="SelectionChanged"
         DayHeaderStyle-BackColor="Black"
         DayHeaderStyle-ForeColor="White"
         DayHeaderStyle-Font-Name="Arial Black"
         runat="server" >

         <DayStyle
            BackColor="White"
            ForeColor="Black"
            Font-Name="Arial" />
         <NextPrevStyle
            BackColor="DarkGray"
            ForeColor="Yellow"
            Font-Name="Arial" />
         <OtherMonthDayStyle
            BackColor="LightGray"
            ForeColor="White"
            Font-Name="Arial" />
         <SelectedDayStyle
            BackColor="CornSilk"
            ForeColor="Blue"
            Font-Name="Arial" 
            Font-Bold="true"
            Font-Italic="true"/>
         <SelectorStyle
            BackColor="CornSilk"
            ForeColor="Red"
            Font-Name="Arial" />
         <TitleStyle
            BackColor="Gray"
            ForeColor="White"
            HorizontalAlign="Left"
            Font-Name="Arial Black" />
         <TodayDayStyle
            BackColor="CornSilk"
            ForeColor="Green"
            Font-Name="Arial" 
            Font-Bold="true"
            Font-Italic="false"/>
         <WeekendDayStyle
            BackColor="LavenderBlush"
            ForeColor="Purple"
            Font-Name="Arial" 
            Font-Bold="false"
            Font-Italic="false"/>
      </asp:Calendar>

      <br/>
      <asp:Label id="lblCount" runat="server" />
      <br/>
      <asp:Label id="lblTodaysDate" runat="server" />
      <br/>
      <asp:Label id="lblSelected" runat="server" />
      <br/>
      <table>
         <tr>
            <td>
               Select a month:
            </td>
            <td>
               <asp:DropDownList 
                  id= "ddl"
                  AutoPostBack="true"
                  onSelectedIndexChanged = "ddl_SelectedIndexChanged"
                  runat="server">

                  <asp:ListItem text="January" value="1" />
                  <asp:ListItem text="February" value="2" />
                  <asp:ListItem text="March" value="3" />
                  <asp:ListItem text="April" value="4" />
                  <asp:ListItem text="May" value="5" />
                  <asp:ListItem text="June" value="6" />
                  <asp:ListItem text="July" value="7" />
                  <asp:ListItem text="August" value="8" />
                  <asp:ListItem text="September" value="9" />
                  <asp:ListItem text="October" value="10" />
                  <asp:ListItem text="November" value="11" />
                  <asp:ListItem text="December" value="12" />

               </asp:DropDownList>
            </td>
            <td>
               <asp:Button
                  id="btnTgif"
                  text="TGIF"
                  onClick="btnTgif_Click"
                  runat="server" />
            </td>
         </tr>
      </table>
   </form>
   </body>
</html>
Example 5-44. Calendar control with additional selection functionality in VB.NET (script block only), vbASPCalendarMoreSelections.aspx
<%@ Page Language="VB"%>
<script  runat="server">
   '  This Page_Load makes the selected days visible first time
   '  the TGIF button is clicked by initializing the VisibleDate
   '  property.
   sub Page_Load(ByVal Sender as Object, _
                 ByVal e as EventArgs) 
      if not IsPostBack then
         cal.VisibleDate = cal.TodaysDate
         ddl.SelectedIndex = cal.VisibleDate.Month - 1
      end if

      lblTodaysDate.Text = "Today's Date is " & _
            cal.TodaysDate.ToShortDateString(  )
   end sub

   sub SelectionChanged(ByVal Sender as Object, _
                        ByVal e as EventArgs)
      lblSelectedUpdate(  )
      lblCountUpdate(  )
   end sub

   sub ddl_SelectedIndexChanged(ByVal Sender as Object, _
                                ByVal e as EventArgs)
      cal.SelectedDates.Clear(  )
      lblSelectedUpdate(  )
      lblCountUpdate(  )
      cal.VisibleDate = new DateTime(cal.VisibleDate.Year, _
                        Int32.Parse(ddl.SelectedItem.Value), 1)
   end sub

   sub btnTgif_Click(ByVal Sender as Object, _
                     ByVal e as EventArgs)
      dim currentMonth as integer = cal.VisibleDate.Month
      dim currentYear as integer = cal.VisibleDate.Year

      cal.SelectedDates.Clear(  )

      dim i as integer
      for i = 1 to System.DateTime.DaysInMonth(currentYear, currentMonth)
         dim dt as DateTime = new DateTime(currentYear, currentMonth, i)
         if dt.DayOfWeek = DayOfWeek.Friday then
            cal.SelectedDates.Add(dt)
         end if
      next

      lblSelectedUpdate(  )
      lblCountUpdate(  )
   end sub

   sub lblCountUpdate(  )
      lblCount.Text = "Count of Days Selected:  " & _
            cal.SelectedDates.Count.ToString(  )
   end sub

   sub lblSelectedUpdate(  )
      if (cal.SelectedDate <> DateTime.MinValue) then
         lblSelected.Text = "The date selected is " & _
               cal.SelectedDate.ToShortDateString(  )
      else
        lblSelected.Text = ""
      end if
   end sub
</script>

The DropDownList control and the TGIF button are in a static HTML table so that you can easily control the layout of the page.

The ListItem objects in the drop-down list contain the names of the months for the Text properties and the number of the month for the Value properties.

The SelectionChanged method has been modified by having the bulk of its code moved into a separate method named lblSelectedUpdate, which updates the Text property of the lblSelected label. This method is then called from SelectionChanged, as well as several other places throughout the code.

The ddl_SelectedIndexChanged event handler method begins by clearing the SelectedDates collection. This is the same in C# and VB.NET except for the closing semicolon in C#:

cal.SelectedDates.Clear(  );

A call is made to the lblSelectedUpdate method to clear the Label control containing the first selected date and to the lblCountUpdate method to clear the Label control containing the count of selected dates. Then the VisibleDate property of the Calendar control is set to the first day of the newly selected month. This is the same in C# and VB.NET except for the closing semicolon in C#:

cal.VisibleDate = new DateTime(cal.VisibleDate.Year,
                  Int32.Parse(ddl.SelectedItem.Value), 1);

The VisibleDate property is of type DateTime; a new DateTime is instantiated. The DateTime object, like many objects in the .NET Framework, uses an overloaded constructor. An object may have more than one constructor; each must be differentiated by having different types of arguments or a different number of arguments.

In this case, you want to instantiate a DateTime object that contains only the date. To do so requires three integer parameters—year, month, and day. The first parameter, cal.VisibleDate.Year, and the last parameter, 1, are both inherently integers. However, the month parameter comes from the Value property of the selected item in the DropDownList control. Recall that the Value property is a string, not an integer, even though the characters it contains look like an integer. Therefore it must be converted to an integer using the statement (the same for C# and VB.NET):

Int32.Parse(ddl.SelectedItem.Value)

The TGIF button is named btnTgif and has an event handler for the Click event, btnTgif_Click. This method iterates over all the days of the currently visible month and tests to see if it is Friday. If so, then it will add that date to the collection of SelectedDates.

First the btnTgif_Click method gets the month and year of the currently visible month, using the VisibleDate property of the Calendar control, which is a DateTime object, and the Month and Year properties of the DateTime object. This is the same in C# and VB.NET except for the closing semicolon in C#:

int currentMonth = cal.VisibleDate.Month;
int currentYear = cal.VisibleDate.Year;

Then it clears all the currently selected dates:

cal.SelectedDates.Clear(  );

Now it does the iteration. The limit part of the for loop is the number of days in the month, as determined by the DaysInMonth property of the DateTime object. The month in question is specified by the currentYear and currentMonth variables:

System.DateTime.DaysInMonth(currentYear, currentMonth)

Once inside the for loop, a DateTime variable called date (in the C# code) or dt (in the VB.NET code) is assigned to each day. Again, the DateTime object is instantiated with parameters for year, month, and day. Then the crucial question becomes, "Is the day of the week for this day a Friday?" If so, then TGIF and add it to the collection of SelectedDates. In C#, this would be done:

DateTime date = new DateTime(currentYear, currentMonth, i);
if (date.DayOfWeek == DayOfWeek.Friday)
    cal.SelectedDates.Add(date);

In VB.NET, you'd use:

dim dt as DateTime = new DateTime(currentYear, currentMonth, i)
if dt.DayOfWeek = DayOfWeek.Friday then
   cal.SelectedDates.Add(dt)
end if

The reason that the two languages use a different variable name in this instance is a consequence of the fact that C# is case-sensitive, while VB.NET is not. In VB.NET, date is equivalent to Date, either of which is a keyword and so cannot be used as a variable name, unless it is enclosed in brackets every time it is used. However, in C#, while Date is a keyword, date is not, so the latter can be used as a variable name.

Finally, after iterating over all the days of the month, call the lblSelectedUpdate method to update the label showing the first selected date and call the lblCountUpdate method to update the label showing the number of days selected.

You will notice that there is now a Page_Load method in the script block. As the comment in the code explains, this makes the page behave correctly the first time the TGIF button is clicked, even before the month is changed. Without this Page_Load event procedure, the page behaves correctly for the TGIF button only after the month has been changed at least once. The btnTgif_Click method uses the VisibleDate property to set the current month and year variables. If that property is not initialized during the initial page load, then the values assigned to those variables will not correspond to the visible month.

In addition, the code to update the label displaying today's data has been moved from the SelectionChanged method to the Page_Load method, because it makes more sense to have it there.

The results of these changes and additions are shown in Figure 5-24.

Figure 5-24. Calendar with month and Friday selection
figs/pan2_0524.gif

The Calendar control also allows the user to select a range of dates. You might expect to be able to use the standard Windows techniques of holding down the Ctrl or Shift keys while clicking on dates, but this does not work. However, you can put controls on the page to select a starting day and ending day. In Example 5-45 (in C#) and Example 5-46 (in VB.NET, script block only since the HTML is identical to that in Example 5-45), add a pair of TextBox controls to accept a starting day and an ending day for a range of dates. There is also a Button control to force the selection of the range of dates.

Example 5-45. Calendar control with date range selection in C#, csASPCalendarRangeSelection.aspx
<%@ Page Language="C#" %>
<script  runat="server">
   //  This Page_Load makes the selected days visible first time
   //  the TGIF button is clicked by initializing the VisibleDate
   //  property.
   void Page_Load(Object sender, EventArgs e) 
   {
      if (!IsPostBack)
     {
         cal.VisibleDate = cal.TodaysDate;
        ddl.SelectedIndex = cal.VisibleDate.Month - 1;
      }
      lblTodaysDate.Text = "Today's Date is " +  
            cal.TodaysDate.ToShortDateString(  );
   }

   void SelectionChanged(Object sender, EventArgs e)
   {
      lblSelectedUpdate(  );
      lblCountUpdate(  );
      txtClear(  );
   }

   void ddl_SelectedIndexChanged(Object sender, EventArgs e)
   {
      cal.SelectedDates.Clear(  );
      lblSelectedUpdate(  );
      lblCountUpdate(  );
      txtClear(  );
      cal.VisibleDate = new DateTime(cal.TodaysDate.Year, 
                        Int32.Parse(ddl.SelectedItem.Value), 1);
   }

   void btnTgif_Click(Object sender, EventArgs e)
   {
      int currentMonth = cal.VisibleDate.Month;
      int currentYear = cal.VisibleDate.Year;

      cal.SelectedDates.Clear(  );

      for (int i = 1; 
               i <= System.DateTime.DaysInMonth(currentYear,
                                                currentMonth); 
               i++ )
      {
         DateTime date = new DateTime(currentYear, currentMonth, i);
         if (date.DayOfWeek == DayOfWeek.Friday)
            cal.SelectedDates.Add(date);
      }

      lblSelectedUpdate(  );
      lblCountUpdate(  );
      txtClear(  );
   }

   void btnRange_Click(Object sender, EventArgs e)
   {
      int currentMonth = cal.VisibleDate.Month;
      int currentYear = cal.VisibleDate.Year;
      DateTime StartDate = new DateTime(currentYear, currentMonth, 
                           Int32.Parse(txtStart.Text));
      DateTime EndDate = new DateTime(currentYear, currentMonth, 
                         Int32.Parse(txtEnd.Text));

      cal.SelectedDates.Clear(  );
      cal.SelectedDates.SelectRange(StartDate, EndDate);

      lblSelectedUpdate(  );
      lblCountUpdate(  );
   }

   void lblCountUpdate(  )
   {
      lblCount.Text = "Count of Days Selected:  " + 
            cal.SelectedDates.Count.ToString(  );
   }

   void lblSelectedUpdate(  )
   {
      if (cal.SelectedDate != DateTime.MinValue)
         lblSelected.Text = "The date selected is " + 
               cal.SelectedDate.ToShortDateString(  );
      else
        lblSelected.Text = "";
   }

   void txtClear(  )
   {
      txtStart.Text = "";
      txtEnd.Text = "";
   }
</script>

<html>
   <body>
   <form runat="server">

      <h1>ASP Controls</h1>
      <h2>Calendar Control</h2>
      <h2>Range Selection</h2>

      <asp:Calendar
         id="cal"
         SelectionMode="DayWeekMonth"
         ShowGridLines="true"
         ShowNextprevMonth="true"
         CellPadding="7"
         CellSpacing="5"
         DayNameFormat="FirstTwoLetters"
         FirstDayOfWeek="Monday"
         NextPrevFormat="CustomText"
         NextMonthText="Next &gt;"
         PrevMonthText="&lt; Prev"
         onSelectionChanged="SelectionChanged"
         DayHeaderStyle-BackColor="Black"
         DayHeaderStyle-ForeColor="White"
         DayHeaderStyle-Font-Name="Arial Black"
         runat="server" >

         <DayStyle
            BackColor="White"
            ForeColor="Black"
            Font-Name="Arial" />
         <NextPrevStyle
            BackColor="DarkGray"
            ForeColor="Yellow"
            Font-Name="Arial" />
         <OtherMonthDayStyle
            BackColor="LightGray"
            ForeColor="White"
            Font-Name="Arial" />
         <SelectedDayStyle
            BackColor="CornSilk"
            ForeColor="Blue"
            Font-Name="Arial" 
            Font-Bold="true"
            Font-Italic="true"/>
         <SelectorStyle
            BackColor="CornSilk"
            ForeColor="Red"
            Font-Name="Arial" />
         <TitleStyle
            BackColor="Gray"
            ForeColor="White"
            HorizontalAlign="Left"
            Font-Name="Arial Black" />
         <TodayDayStyle
            BackColor="CornSilk"
            ForeColor="Green"
            Font-Name="Arial" 
            Font-Bold="true"
            Font-Italic="false"/>
         <WeekendDayStyle
            BackColor="LavenderBlush"
            ForeColor="Purple"
            Font-Name="Arial" 
            Font-Bold="false"
            Font-Italic="false"/>
      </asp:Calendar>

      <br/>
      <asp:Label id="lblCount" runat="server" />
      <br/>
      <asp:Label id="lblTodaysDate" runat="server" />
      <br/>
      <asp:Label id="lblSelected" runat="server" />
      <br/>
      <table>
         <tr>
            <td>
               Select a month:
            </td>
            <td>
               <asp:DropDownList 
                  id= "ddl"
                  AutoPostBack="true"
                  onSelectedIndexChanged = "ddl_SelectedIndexChanged"
                  runat="server">

                  <asp:ListItem text="January" value="1" />
                  <asp:ListItem text="February" value="2" />
                  <asp:ListItem text="March" value="3" />
                  <asp:ListItem text="April" value="4" />
                  <asp:ListItem text="May" value="5" />
                  <asp:ListItem text="June" value="6" />
                  <asp:ListItem text="July" value="7" />
                  <asp:ListItem text="August" value="8" />
                  <asp:ListItem text="September" value="9" />
                  <asp:ListItem text="October" value="10" />
                  <asp:ListItem text="November" value="11" />
                  <asp:ListItem text="December" value="12" />

               </asp:DropDownList>
            </td>
            <td>
               <asp:Button
                  id="btnTgif"
                  text="TGIF"
                  onClick="btnTgif_Click"
                  runat="server" />
            </td>
         </tr>
         <tr>
            <td colspan="2">&nbsp;</td>
         </tr>
         <tr>
            <td colspan="2"><b>Day Range</b></td>
         </tr>
         <tr>
            <td>Starting Day</td>
            <td>Ending Day</td>
         </tr>
         <tr>
            <td>
               <asp:TextBox 
                  id= "txtStart"
                  Size="2"
                  MaxLength="2"
                  runat="server" />
            </td>
            <td>
               <asp:TextBox 
                  id= "txtEnd"
                  Size="2"
                  MaxLength="2"
                  runat="server" />
            </td>
            <td>
               <asp:Button
                  id="btnRange"
                  text="Apply"
                  onClick="btnRange_Click"
                  runat="server" />
            </td>
         </tr>
      </table>
   </form>
   </body>
</html>
Example 5-46. Calendar control with date range selection in VB.NET (script block only), vbASPCalendarRangeSelection.aspx
<%@ Page Language="VB"%>
<script  runat="server">
   '  This Page_Load makes the selected days visible first time
   '  the TGIF button is clicked by initializing the VisibleDate
   '  property.
   sub Page_Load(ByVal Sender as Object, _
                 ByVal e as EventArgs) 
      if not IsPostBack then
         cal.VisibleDate = cal.TodaysDate
         ddl.SelectedIndex = cal.VisibleDate.Month - 1
      end if

      lblTodaysDate.Text = "Today's Date is " & _
            cal.TodaysDate.ToShortDateString(  )
   end sub

   sub SelectionChanged(ByVal Sender as Object, _
                        ByVal e as EventArgs)
      lblSelectedUpdate(  )
      lblCountUpdate(  )
      txtClear(  )
   end sub

   sub ddl_SelectedIndexChanged(ByVal Sender as Object, _
                                ByVal e as EventArgs)
      cal.SelectedDates.Clear(  )
      lblSelectedUpdate(  )
      lblCountUpdate(  )
      txtClear(  )
      cal.VisibleDate = new DateTime(cal.TodaysDate.Year, _
                        Int32.Parse(ddl.SelectedItem.Value), 1)
   end sub

   sub btnTgif_Click(ByVal Sender as Object, _
                     ByVal e as EventArgs)
      dim currentMonth as integer = cal.VisibleDate.Month
      dim currentYear as integer = cal.VisibleDate.Year

      cal.SelectedDates.Clear(  )

      dim i as integer
      for i = 1 to System.DateTime.DaysInMonth(currentYear, _
                                               currentMonth)
         dim dt as DateTime = new DateTime(currentYear, _
                                           currentMonth, _
                                           i)
         if dt.DayOfWeek = DayOfWeek.Friday then
            cal.SelectedDates.Add(dt)
         end if
      next

      lblSelectedUpdate(  )
      lblCountUpdate(  )
      txtClear(  )
   end sub

   sub btnRange_Click(ByVal Sender as Object, _
                      ByVal e as EventArgs)
      dim currentMonth as integer = cal.VisibleDate.Month
      dim currentYear as integer = cal.VisibleDate.Year
      dim StartDate as DateTime = new DateTime(currentYear, _
                                               currentMonth, _
                                               Int32.Parse(txtStart.Text))
      dim EndDate as DateTime = new DateTime(currentYear, _
                                             currentMonth, _
                                             Int32.Parse(txtEnd.Text))
      cal.SelectedDates.Clear(  )
      cal.SelectedDates.SelectRange(StartDate, EndDate)

      lblCountUpdate(  )
   end sub

   sub lblCountUpdate(  )
      lblCount.Text = "Count of Days Selected:  " & _
            cal.SelectedDates.Count.ToString(  )
   end sub

   sub lblSelectedUpdate(  )
      if (cal.SelectedDate <> DateTime.MinValue) then
         lblSelected.Text = "The date selected is " & _
               cal.SelectedDate.ToShortDateString(  )
      else
        lblSelected.Text = ""
      end if
   end sub

   sub txtClear(  )
      txtStart.Text = ""
      txtEnd.Text = ""
   end sub
</script>

This UI is admittedly somewhat limiting because you cannot span multiple months. You could almost as easily provide three independent Calendar controls—one for the start date, one for the end date, and one for the range. Also, the day range does not apply after the month changes without reapplying the selection because the VisibleMonthChanged event is not trapped. (See "VisibleMonthChanged event" later in this chapter.)

The controls for selecting the range are in the same static HTML table as the controls described previously for selecting the month and all the Fridays. There are two text boxes, one named txtStart for the start day and one named txtEnd for the end day. In this example, the TextBox controls' Size and MaxLength attributes provide limited control over the user input. In a production application you will want to add validation controls as described in Chapter 8.

A new method, txtClear, is provided to clear out the day range selection boxes. This method is called at appropriate points in the other methods.

The Apply button is named btnRange, with the Click event handled by the method btnRange_Click. In btnRange_Click, you set integer variables to hold the current month and year. In C#, the code is:

int currentMonth = cal.VisibleDate.Month;
int currentYear = cal.VisibleDate.Year;

In VB.NET, it is:

dim currentMonth as integer = cal.VisibleDate.Month
dim currentYear as integer = cal.VisibleDate.Year

Set two DateTime variables to hold the start date and the end date. In C#, you would write:

DateTime StartDate = new DateTime(currentYear, currentMonth, 
                                  Int32.Parse(txtStart.Text));
DateTime EndDate = new DateTime(currentYear, currentMonth, Int32.Parse(txtEnd.Text));

In VB.NET, the code is:

dim StartDate as DateTime = new DateTime(currentYear, _
                 currentMonth, _
                 Int32.Parse(txtStart.Text))
dim EndDate as DateTime = new DateTime(currentYear, _
                 currentMonth, _
                 Int32.Parse(txtEnd.Text))

Similarly to the month DropDownList described previously, the DateTime object requires the year, month, and day. You already have the year and month as integers; all you need is the day. You get the day by converting the text entered in the appropriate text box to an integer.

This is not very robust code. If the user enters non-numeric data in one of the text boxes, or a value greater than the number of days in the month, an ugly error will result. If the start date is later than the end date, no error message will result, but neither will anything be selected. In a real application, you will want to use validation controls as described in Chapter 8.

Once the method has the start and end dates as DateTime objects, it clears any currently selected dates and uses the SelectRange method to add the range of dates to the SelectedDates collection. This is the same in both C# and VB.NET, except for the trailing semicolon in C#:

cal.SelectedDates.Clear(  );
cal.SelectedDates.SelectRange(StartDate, EndDate);

The SelectRange method requires two parameters: the start date and the end date.

The result of adding the selection tools to the page is shown in Figure 5-25.

Figure 5-25. Calendar with range selection
figs/pan2_0525.gif
5.11.1.2 DayRender event

Data binding is not supported directly for the Calendar control. However, you can modify the content and formatting of individual date cells. This allows you to retrieve values from a database, process those values in some manner, and place them in specific cells.

Before the Calendar control is actually rendered to the client browser, all of the components that comprise the control are created. As each date cell is created, it raises the DayRender event. This event can be handled.

The DayRender event handler receives an argument of type DayRenderEventArgs. This object has two properties that may be programmatically read:

Cell

TableCell object that represents the cell being rendered

Day

CalendarDay object that represents the day being rendered in that cell.

The code in Example 5-47 and Example 5-48 demonstrates how this event can be used. All the weekend days will have their background color changed and a New Year's greeting will be displayed for January 1.

Example 5-47 shows the complete .aspx page with script written in C# while Example 5-48 shows only the VB code, since its HTML content is the same as Example 5-47 The examples are modified versions of Example 5-45 and Example 5-46, with added lines shown in boldface.

Example 5-47. DayRender event in C#, csASPCalendarDayRender.aspx
<%@ Page Language="C#" %>
<script  runat="server">
   //  This Page_Load makes the selected days visible first time
   //  the TGIF button is clicked by initializing the VisibleDate
   //  property.
   void Page_Load(Object sender, EventArgs e) 
   {
      if (!IsPostBack)
     {
         cal.VisibleDate = cal.TodaysDate;
        ddl.SelectedIndex = cal.VisibleDate.Month - 1;
      }
      lblTodaysDate.Text = "Today's Date is " +  
            cal.TodaysDate.ToShortDateString(  );
   }

   void SelectionChanged(Object sender, EventArgs e)
   {
      lblSelectedUpdate(  );
      lblCountUpdate(  );
      txtClear(  );
   }
void ddl_SelectedIndexChanged(Object sender, EventArgs e)
   {
      cal.SelectedDates.Clear(  );
      lblSelectedUpdate(  );
      lblCountUpdate(  );
      txtClear(  );
      cal.VisibleDate = new DateTime(cal.TodaysDate.Year, 
                        Int32.Parse(ddl.SelectedItem.Value), 1);
   }

   void btnTgif_Click(Object sender, EventArgs e)
   {
      int currentMonth = cal.VisibleDate.Month;
      int currentYear = cal.VisibleDate.Year;

      cal.SelectedDates.Clear(  );

      for (int i = 1; 
               i <= System.DateTime.DaysInMonth(currentYear, 
                                                currentMonth); 
               i++ )
      {
         DateTime date = new DateTime(currentYear, currentMonth, i);
         if (date.DayOfWeek == DayOfWeek.Friday)
            cal.SelectedDates.Add(date);
      }

      lblSelectedUpdate(  );
      lblCountUpdate(  );
      txtClear(  );
   }

   void btnRange_Click(Object sender, EventArgs e)
   {
      int currentMonth = cal.VisibleDate.Month;
      int currentYear = cal.VisibleDate.Year;
      DateTime StartDate = new DateTime(currentYear, currentMonth, 
                           Int32.Parse(txtStart.Text));
      DateTime EndDate = new DateTime(currentYear, currentMonth, 
                         Int32.Parse(txtEnd.Text));

      cal.SelectedDates.Clear(  );
      cal.SelectedDates.SelectRange(StartDate, EndDate);

      lblSelectedUpdate(  );
      lblCountUpdate(  );
   }

   void DayRender(Object sender, DayRenderEventArgs e)
   {
      //  Notice that this overrides the WeekendDayStyle.
      if (!e.Day.IsOtherMonth && e.Day.IsWeekend)
         e.Cell.BackColor=System.Drawing.Color.LightGreen;

      //  Happy New Year!
      if (e.Day.Date.Month == 1 && e.Day.Date.Day == 1)
         e.Cell.Controls.Add(new LiteralControl("<br/>Happy New Year!"));
   }

   void lblCountUpdate(  )
   {
      lblCount.Text = "Count of Days Selected:  " + 
            cal.SelectedDates.Count.ToString(  );
   }

   void lblSelectedUpdate(  )
   {
      if (cal.SelectedDate != DateTime.MinValue)
         lblSelected.Text = "The date selected is " + 
               cal.SelectedDate.ToShortDateString(  );
      else
        lblSelected.Text = "";
   }

   void txtClear(  )
   {
      txtStart.Text = "";
      txtEnd.Text = "";
   }
</script>

<html>
   <body>
   <form runat="server">

      <h1>ASP Controls</h1>
      <h2>Calendar Control</h2>
      <h2>DayRender</h2>

      <asp:Calendar
         id="cal"
         SelectionMode="DayWeekMonth"
         ShowGridLines="true"
         ShowNextprevMonth="true"
         CellPadding="7"
         CellSpacing="5"
         DayNameFormat="FirstTwoLetters"
         FirstDayOfWeek="Monday"
         NextPrevFormat="CustomText"
         NextMonthText="Next &gt;"
         PrevMonthText="&lt; Prev"
         onSelectionChanged="SelectionChanged"
         onDayRender="DayRender"
         DayHeaderStyle-BackColor="Black"
         DayHeaderStyle-ForeColor="White"
         DayHeaderStyle-Font-Name="Arial Black"
         runat="server" >

         <DayStyle
            BackColor="White"
            ForeColor="Black"
            Font-Name="Arial" />
         <NextPrevStyle
            BackColor="DarkGray"
            ForeColor="Yellow"
            Font-Name="Arial" />
         <OtherMonthDayStyle
            BackColor="LightGray"
            ForeColor="White"
            Font-Name="Arial" />
         <SelectedDayStyle
            BackColor="CornSilk"
            ForeColor="Blue"
            Font-Name="Arial" 
            Font-Bold="true"
            Font-Italic="true"/>
         <SelectorStyle
            BackColor="CornSilk"
            ForeColor="Red"
            Font-Name="Arial" />
         <TitleStyle
            BackColor="Gray"
            ForeColor="White"
            HorizontalAlign="Left"
            Font-Name="Arial Black" />
         <TodayDayStyle
            BackColor="CornSilk"
            ForeColor="Green"
            Font-Name="Arial" 
            Font-Bold="true"
            Font-Italic="false"/>
         <WeekendDayStyle
            BackColor="LavenderBlush"
            ForeColor="Purple"
            Font-Name="Arial" 
            Font-Bold="false"
            Font-Italic="false"/>
      </asp:Calendar>

      <br/>
      <asp:Label id="lblCount" runat="server" />
      <br/>
      <asp:Label id="lblTodaysDate" runat="server" />
      <br/>
      <asp:Label id="lblSelected" runat="server" />
      <br/>
      <table>
         <tr>
            <td>
               Select a month:
            </td>
            <td>
               <asp:DropDownList 
                  id= "ddl"
                  AutoPostBack="true"
                  onSelectedIndexChanged = "ddl_SelectedIndexChanged"
                  runat="server">

                  <asp:ListItem text="January" value="1" />
                  <asp:ListItem text="February" value="2" />
                  <asp:ListItem text="March" value="3" />
                  <asp:ListItem text="April" value="4" />
                  <asp:ListItem text="May" value="5" />
                  <asp:ListItem text="June" value="6" />
                  <asp:ListItem text="July" value="7" />
                  <asp:ListItem text="August" value="8" />
                  <asp:ListItem text="September" value="9" />
                  <asp:ListItem text="October" value="10" />
                  <asp:ListItem text="November" value="11" />
                  <asp:ListItem text="December" value="12" />

               </asp:DropDownList>
            </td>
            <td>
               <asp:Button
                  id="btnTgif"
                  text="TGIF"
                  onClick="btnTgif_Click"
                  runat="server" />
            </td>
         </tr>
         <tr>
            <td colspan="2">&nbsp;</td>
         </tr>
         <tr>
            <td colspan="2"><b>Day Range</b></td>
         </tr>
         <tr>
            <td>Starting Day</td>
            <td>Ending Day</td>
         </tr>
         <tr>
            <td>
               <asp:TextBox 
                  id= "txtStart"
                  Size="2"
                  MaxLength="2"
                  runat="server" />
            </td>
            <td>
               <asp:TextBox 
                  id= "txtEnd"
                  Size="2"
                  MaxLength="2"
                  runat="server" />
            </td>
            <td>
               <asp:Button
                  id="btnRange"
                  text="Apply"
                  onClick="btnRange_Click"
                  runat="server" />
            </td>
         </tr>
      </table>
   </form>
   </body>
</html>
Example 5-48. DayRender event in VB.NET, vbASPCalendarDayRender.aspx
<%@ Page Language="VB"%>
<script  runat="server">
   '  This Page_Load makes the selected days visible first time
   '  the TGIF button is clicked by initializing the VisibleDate
   '  property.
   sub Page_Load(ByVal Sender as Object, _
                 ByVal e as EventArgs) 
      if not IsPostBack then
         cal.VisibleDate = cal.TodaysDate
       ddl.SelectedIndex = cal.VisibleDate.Month - 1
      end if

      lblTodaysDate.Text = "Today's Date is " & _
            cal.TodaysDate.ToShortDateString(  )
   end sub

   sub SelectionChanged(ByVal Sender as Object, _
                        ByVal e as EventArgs)
      lblSelectedUpdate(  )
      lblCountUpdate(  )
      txtClear(  )
   end sub

   sub ddl_SelectedIndexChanged(ByVal Sender as Object, _
                                ByVal e as EventArgs)
      cal.SelectedDates.Clear(  )
      lblSelectedUpdate(  )
      lblCountUpdate(  )
      txtClear(  )
      cal.VisibleDate = new DateTime(cal.TodaysDate.Year, _
                        Int32.Parse(ddl.SelectedItem.Value), 1)
   end sub

   sub btnTgif_Click(ByVal Sender as Object, _
                     ByVal e as EventArgs)
      dim currentMonth as integer = cal.VisibleDate.Month
      dim currentYear as integer = cal.VisibleDate.Year

      cal.SelectedDates.Clear(  )

      dim i as integer
      for i = 1 to System.DateTime.DaysInMonth(currentYear, _
                                               currentMonth)
         dim dt as DateTime = new DateTime(currentYear, _
                                           currentMonth, _
                                           i)
         if dt.DayOfWeek = DayOfWeek.Friday then
            cal.SelectedDates.Add(dt)
         end if
      next

      lblSelectedUpdate(  )
      lblCountUpdate(  )
      txtClear(  )
   end sub

   sub btnRange_Click(ByVal Sender as Object, _
                      ByVal e as EventArgs)
      dim currentMonth as integer = cal.VisibleDate.Month
      dim currentYear as integer = cal.VisibleDate.Year
      dim StartDate as DateTime = new DateTime(currentYear, _
                                               currentMonth, _
                                               Int32.Parse(txtStart.Text))
      dim EndDate as DateTime = new DateTime(currentYear, _
                                             currentMonth, _
                                             Int32.Parse(txtEnd.Text))
      cal.SelectedDates.Clear(  )
      cal.SelectedDates.SelectRange(StartDate, EndDate)

      lblCountUpdate(  )
   end sub

   sub DayRender(ByVal Sender as Object, _
                 ByVal e as DayRenderEventArgs)
      '  Notice that this overrides the WeekendDayStyle.
      if (not e.Day.IsOtherMonth and e.Day.IsWeekend) then
         e.Cell.BackColor=System.Drawing.Color.LightGreen
      end if

      '  Happy New Year!
      if (e.Day.Date.Month = 1 and e.Day.Date.Day = 1) then
         e.Cell.Controls.Add(new LiteralControl("<br/>Happy New Year!"))
      end if
   end sub

   sub lblCountUpdate(  )
      lblCount.Text = "Count of Days Selected:  " & _
            cal.SelectedDates.Count.ToString(  )
   end sub

   sub lblSelectedUpdate(  )
      if (cal.SelectedDate <> DateTime.MinValue) then
         lblSelected.Text = "The date selected is " & _
               cal.SelectedDate.ToShortDateString(  )
      else
        lblSelected.Text = ""
      end if
   end sub

   sub txtClear(  )
      txtStart.Text = ""
      txtEnd.Text = ""
   end sub
</script>

In Example 5-47 and Example 5-48, an event handler, onDayRender, was added to the Calendar control. This event handler points to the DayRender method, contained in the script block.

The first thing the DayRender method does is color the weekends LightGreen. Recall that there is a WeekendDayStyle property set for this control that colors the weekends LavenderBlush. The DayRender method overrides the WeekendDayStyle. (The distinction may not be readily apparent in the printed book, but you will see the colors when the web page is run.)

The event handler method is passed two parameters. In C#, this is accomplished with:

void DayRender(Object sender, DayRenderEventArgs e)

In VB.NET, the code is:

sub DayRender(ByVal Sender as Object, _
              ByVal e as DayRenderEventArgs)

DayRenderEventArgs contains properties for the Day and the Cell. The Day is tested to see if it is both the current month and also a weekend day. In C#, the code is:

(!e.Day.IsOtherMonth && e.Day.IsWeekend)

In VB.NET, the code is:

(not e.Day.IsOtherMonth and e.Day.IsWeekend)

The Day property is a member of the CalendarDay class, which has the properties shown in Table 5-28 (all of which are read-only except IsSelectable).

Table 5-28. Properties of the CalendarDay class

Property

Type

Description

Date

DateTime

Date represented by this Day. Read-only.

DayNumberText

String

String representation of the day number of this Day. Read-only.

IsOtherMonth

Boolean

Indicates this Day is in a different month than the month currently displayed by the Calendar. Read-only.

IsSelectable

Boolean

Indicates if Day can be selected. Not read-only.

IsSelected

Boolean

Indicates if Day is selected.

IsToday

Boolean

Indicates if Day is today's date.

IsWeekend

Boolean

Indicates if Day is a weekend date.

If the date is both in the current month and is also a weekend day, then the Cell.BackColor property is assigned a color. This is the same in C# and VB.NET except for the trailing semicolon in C#:

e.Cell.BackColor=System.Drawing.Color.LightGreen;

and Example 5-48 then test to see if the selected date is New Year's day. Again, the Day property of the DayRenderEventArgs object is tested to see if the month of the Date is 1 and the Day of the Date is 1. In C#, this is done using the code:

if (e.Day.Date.Month == 1 && e.Day.Date.Day == 1)

In VB.NET, the code is:

if (e.Day.Date.Month = 1 and e.Day.Date.Day = 1) then

If so, a LiteralControl is added to the cell that adds an HTML break tag and a greeting. This is the same in C# and VB.NET except for the trailing semicolon in C#:

e.Cell.Controls.Add(new LiteralControl("<br/>Happy New Year!"));

The thing to remember here is that, like all ASP controls, what is actually sent to the browser is HTML. Thus, a Calendar is rendered on the browser as an HTML table. Each of the selectable components of the calendar has an anchor tag associated with it, along with some JavaScript that accomplishes the postback. (This is evident when you hover the cursor over any clickable element of the calendar—the status line of the browser will display the name of the JavaScript function that will be executed if the link is clicked.) Using a LiteralControl inserts the text in its argument as a control into the HTML cell as-is. A look at a snippet from the source code visible on the browser confirms this:

<td align="Center" style="color:Black;background-color:White;
                          font-family:Arial;width:12%;">
    <a href="javascript:_  _doPostBack('cal','selectDay7')" style="color:Black">
    1
    </a>
    <br/>Happy New Year!
</td>

When the code from Example 5-47 or Example 5-48 is run, you get the results shown in Figure 5-26.

Figure 5-26. Calendar with DayRender event
figs/pan2_0526.gif
5.11.1.3 VisibleMonthChanged event

The Calendar control also provides an event to indicate that the user has changed months. In Example 5-49, you add an event handler in C# for the VisibleMonthChanged event. Example 5-50 shows the same event handler in VB.NET.

Example 5-49. VisibleMonthChanged event in C#, csASPCalendarVisibleMonth.aspx
<%@ Page Language="C#" %>
<script  runat="server">
   //  This Page_Load makes the selected days visible first time
   //  the TGIF button is clicked by initializing the VisibleDate
   //  property.
   void Page_Load(Object sender, EventArgs e) 
   {
      if (!IsPostBack)
     {
         cal.VisibleDate = cal.TodaysDate;
        ddl.SelectedIndex = cal.VisibleDate.Month - 1;
      }
      lblTodaysDate.Text = "Today's Date is " +  
            cal.TodaysDate.ToShortDateString(  );
   }

   void SelectionChanged(Object sender, EventArgs e)
   {
      lblSelectedUpdate(  );
      lblCountUpdate(  );
      txtClear(  );
   }

   void ddl_SelectedIndexChanged(Object sender, EventArgs e)
   {
      cal.SelectedDates.Clear(  );
      lblSelectedUpdate(  );
      lblCountUpdate(  );
      txtClear(  );
      cal.VisibleDate = new DateTime(cal.TodaysDate.Year, 
                        Int32.Parse(ddl.SelectedItem.Value), 1);
   }

   void btnTgif_Click(Object sender, EventArgs e)
   {
      int currentMonth = cal.VisibleDate.Month;
      int currentYear = cal.VisibleDate.Year;

      cal.SelectedDates.Clear(  );

      for (int i = 1; 
               i <= System.DateTime.DaysInMonth(currentYear, 
                                                currentMonth); 
               i++ )
      {
         DateTime date = new DateTime(currentYear, currentMonth, i);
         if (date.DayOfWeek == DayOfWeek.Friday)
            cal.SelectedDates.Add(date);
      }

      lblSelectedUpdate(  );
      lblCountUpdate(  );
      txtClear(  );
   }

   void btnRange_Click(Object sender, EventArgs e)
   {
      int currentMonth = cal.VisibleDate.Month;
      int currentYear = cal.VisibleDate.Year;
      DateTime StartDate = new DateTime(currentYear, currentMonth, 
                           Int32.Parse(txtStart.Text));
      DateTime EndDate = new DateTime(currentYear, currentMonth, 
                         Int32.Parse(txtEnd.Text));

      cal.SelectedDates.Clear(  );
      cal.SelectedDates.SelectRange(StartDate, EndDate);

      lblSelectedUpdate(  );
      lblCountUpdate(  );
   }

   void DayRender(Object sender, DayRenderEventArgs e)
   {
      //  Notice that this overrides the WeekendDayStyle.
      if (!e.Day.IsOtherMonth && e.Day.IsWeekend)
         e.Cell.BackColor=System.Drawing.Color.LightGreen;

      //  Happy New Year!
      if (e.Day.Date.Month == 1 && e.Day.Date.Day == 1)
         e.Cell.Controls.Add(new LiteralControl("<br/>Happy New Year!"));
   }

   void VisibleMonthChanged(Object sender, MonthChangedEventArgs e)
   {
      if ((e.NewDate.Year > e.PreviousDate.Year) ||
         ((e.NewDate.Year == e.PreviousDate.Year) && 
         (e.NewDate.Month > e.PreviousDate.Month)))
         lblMonthChanged.Text = "My future's so bright...";
      else
         lblMonthChanged.Text = "Back to the future!";

      cal.SelectedDates.Clear(  );
      lblSelectedUpdate(  );
      lblCountUpdate(  );
      txtClear(  );
   }

   void lblCountUpdate(  )
   {
      lblCount.Text = "Count of Days Selected:  " + 
            cal.SelectedDates.Count.ToString(  );
   }

   void lblSelectedUpdate(  )
   {
      if (cal.SelectedDate != DateTime.MinValue)
         lblSelected.Text = "The date selected is " + 
               cal.SelectedDate.ToShortDateString(  );
      else
        lblSelected.Text = "";
   }

   void txtClear(  )
   {
      txtStart.Text = "";
      txtEnd.Text = "";
   }
</script>

<html>
   <body>
   <form runat="server">

      <h1>ASP Controls</h1>
      <h2>Calendar Control</h2>
      <h2>VisibleMonthChanged Event</h2>

      <asp:Label id="lblMonthChanged" runat="server" />

      <asp:Calendar
         id="cal"
         SelectionMode="DayWeekMonth"
         ShowGridLines="true"
         ShowNextprevMonth="true"
         CellPadding="7"
         CellSpacing="5"
         DayNameFormat="FirstTwoLetters"
         FirstDayOfWeek="Monday"
         NextPrevFormat="CustomText"
         NextMonthText="Next &gt;"
         PrevMonthText="&lt; Prev"
         onSelectionChanged="SelectionChanged"
         onDayRender="DayRender"
         onVisibleMonthChanged="VisibleMonthChanged"
         DayHeaderStyle-BackColor="Black"
         DayHeaderStyle-ForeColor="White"
         DayHeaderStyle-Font-Name="Arial Black"
         runat="server" >

         <DayStyle
            BackColor="White"
            ForeColor="Black"
            Font-Name="Arial" />
         <NextPrevStyle
            BackColor="DarkGray"
            ForeColor="Yellow"
            Font-Name="Arial" />
         <OtherMonthDayStyle
            BackColor="LightGray"
            ForeColor="White"
            Font-Name="Arial" />
         <SelectedDayStyle
            BackColor="CornSilk"
            ForeColor="Blue"
            Font-Name="Arial" 
            Font-Bold="true"
            Font-Italic="true"/>
         <SelectorStyle
            BackColor="CornSilk"
            ForeColor="Red"
            Font-Name="Arial" />
         <TitleStyle
            BackColor="Gray"
            ForeColor="White"
            HorizontalAlign="Left"
            Font-Name="Arial Black" />
         <TodayDayStyle
            BackColor="CornSilk"
            ForeColor="Green"
            Font-Name="Arial" 
            Font-Bold="true"
            Font-Italic="false"/>
         <WeekendDayStyle
            BackColor="LavenderBlush"
            ForeColor="Purple"
            Font-Name="Arial" 
            Font-Bold="false"
            Font-Italic="false"/>
      </asp:Calendar>

      <br/>
      <asp:Label id="lblCount" runat="server" />
      <br/>
      <asp:Label id="lblTodaysDate" runat="server" />
      <br/>
      <asp:Label id="lblSelected" runat="server" />
      <br/>
      <table>
         <tr>
            <td>
               Select a month:
            </td>
            <td>
               <asp:DropDownList 
                  id= "ddl"
                  AutoPostBack="true"
                  onSelectedIndexChanged = "ddl_SelectedIndexChanged"
                  runat="server">

                  <asp:ListItem text="January" value="1" />
                  <asp:ListItem text="February" value="2" />
                  <asp:ListItem text="March" value="3" />
                  <asp:ListItem text="April" value="4" />
                  <asp:ListItem text="May" value="5" />
                  <asp:ListItem text="June" value="6" />
                  <asp:ListItem text="July" value="7" />
                  <asp:ListItem text="August" value="8" />
                  <asp:ListItem text="September" value="9" />
                  <asp:ListItem text="October" value="10" />
                  <asp:ListItem text="November" value="11" />
                  <asp:ListItem text="December" value="12" />

               </asp:DropDownList>
            </td>
            <td>
               <asp:Button
                  id="btnTgif"
                  text="TGIF"
                  onClick="btnTgif_Click"
                  runat="server" />
            </td>
         </tr>
         <tr>
            <td colspan="2">&nbsp;</td>
         </tr>
         <tr>
            <td colspan="2"><b>Day Range</b></td>
         </tr>
         <tr>
            <td>Starting Day</td>
            <td>Ending Day</td>
         </tr>
         <tr>
            <td>
               <asp:TextBox 
                  id= "txtStart"
                  Size="2"
                  MaxLength="2"
                  runat="server" />
            </td>
            <td>
               <asp:TextBox 
                  id= "txtEnd"
                  Size="2"
                  MaxLength="2"
                  runat="server" />
            </td>
            <td>
               <asp:Button
                  id="btnRange"
                  text="Apply"
                  onClick="btnRange_Click"
                  runat="server" />
            </td>
         </tr>
      </table>
   </form>
   </body>
</html>
Example 5-50. VisibleMonthChanged event in VB.NET (script block only), vbASPCalendarVisibleMonth.aspx
<%@ Page Language="VB"%>
<script  runat="server">
   '  This Page_Load makes the selected days visible first time
   '  the TGIF button is clicked by initializing the VisibleDate
   '  property.
   sub Page_Load(ByVal Sender as Object, _
                 ByVal e as EventArgs) 
      if not IsPostBack then
         cal.VisibleDate = cal.TodaysDate
       ddl.SelectedIndex = cal.VisibleDate.Month - 1
      end if

      lblTodaysDate.Text = "Today's Date is " & _
            cal.TodaysDate.ToShortDateString(  )
   end sub

   sub SelectionChanged(ByVal Sender as Object, _
                        ByVal e as EventArgs)
      lblSelectedUpdate(  )
      lblCountUpdate(  )
      txtClear(  )
   end sub

   sub ddl_SelectedIndexChanged(ByVal Sender as Object, _
                                ByVal e as EventArgs)
      cal.SelectedDates.Clear(  )
      lblSelectedUpdate(  )
      lblCountUpdate(  )
      txtClear(  )
      cal.VisibleDate = new DateTime(cal.TodaysDate.Year, _
                        Int32.Parse(ddl.SelectedItem.Value), 1)
   end sub

   sub btnTgif_Click(ByVal Sender as Object, _
                     ByVal e as EventArgs)
      dim currentMonth as integer = cal.VisibleDate.Month
      dim currentYear as integer = cal.VisibleDate.Year

      cal.SelectedDates.Clear(  )

      dim i as integer
      for i = 1 to System.DateTime.DaysInMonth(currentYear, _
                                               currentMonth)
         dim dt as DateTime = new DateTime(currentYear, _
                                           currentMonth, _
                                           i)
         if dt.DayOfWeek = DayOfWeek.Friday then
            cal.SelectedDates.Add(dt)
         end if
      next

      lblSelectedUpdate(  )
      lblCountUpdate(  )
      txtClear(  )
   end sub

   sub btnRange_Click(ByVal Sender as Object, _
                      ByVal e as EventArgs)
      dim currentMonth as integer = cal.VisibleDate.Month
      dim currentYear as integer = cal.VisibleDate.Year
      dim StartDate as DateTime = new DateTime(currentYear, _
                                               currentMonth, _
                                               Int32.Parse(txtStart.Text))
      dim EndDate as DateTime = new DateTime(currentYear, _
                                             currentMonth, _
                                             Int32.Parse(txtEnd.Text))
      cal.SelectedDates.Clear(  )
      cal.SelectedDates.SelectRange(StartDate, EndDate)

      lblCountUpdate(  )
   end sub

   sub DayRender(ByVal Sender as Object, _
                 ByVal e as DayRenderEventArgs)
      '  Notice that this overrides the WeekendDayStyle.
      if (not e.Day.IsOtherMonth and e.Day.IsWeekend) then
         e.Cell.BackColor=System.Drawing.Color.LightGreen
      end if

      '  Happy New Year!
      if (e.Day.Date.Month = 1 and e.Day.Date.Day = 1) then
         e.Cell.Controls.Add(new LiteralControl("<br/>Happy New Year!"))
      end if
   end sub

   sub VisibleMonthChanged(ByVal Sender as Object, _
                           ByVal e as MonthChangedEventArgs)
      if e.NewDate.Year > e.PreviousDate.Year Or _
         ((e.NewDate.Year = e.PreviousDate.Year) And _
         (e.NewDate.Month > e.PreviousDate.Month)) Then
         lblMonthChanged.Text = "My future's so bright..."
      else
         lblMonthChanged.Text = "Back to the future!"
      end if

      cal.SelectedDates.Clear(  )
      lblSelectedUpdate(  )
      lblCountUpdate(  )
      txtClear(  )
   end sub

   sub lblCountUpdate(  )
      lblCount.Text = "Count of Days Selected:  " & _
            cal.SelectedDates.Count.ToString(  )
   end sub

   sub lblSelectedUpdate(  )
      if (cal.SelectedDate <> DateTime.MinValue) then
         lblSelected.Text = "The date selected is " & _
               cal.SelectedDate.ToShortDateString(  )
      else
        lblSelected.Text = ""
      end if
   end sub

   sub txtClear(  )
      txtStart.Text = ""
      txtEnd.Text = ""
   end sub
</script>

The onVisibleMonthChanged event handler calls the VisibleMonthChanged method, which is in the script block. A Label control named lblMonthChanged was added just before the Calendar control.

The VisibleMonthChanged event handler method receives an argument of type MonthChangedEventArgs. This argument contains two properties that may be read programmatically:

NewDate

Represents the month currently displayed by the Calendar

PreviousDate

Represents the month previously displayed by the Calendar

These values are tested in the VisibleMonthChanged method to see which came first. Depending on the results, one of two text strings is assigned to the Text property of lblMonthChanged.

Finally, the selected dates are cleared from the calendar, the text strings below the calendar are updated, and the day range edit boxes are cleared with the following lines of code (which are the same in C# and VB.NET, except for the trailing semicolons in C#):

cal.SelectedDates.Clear(  )
lblSelectedUpdate(  )
lblCountUpdate(  )
txtClear(  )

The results of running the pages in Example 5-49 and Example 5-50 can be seen in Figure 5-27.

Figure 5-27. Calendar with VisibleMonthChanged event
figs/pan2_0527.gif
    Previous Section Next Section


    JavaScript Editor Javascript validator     Javascripts 




    ©