5.11 CalendarThe ASP Calendar control is a rich web control that provides several capabilities:
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 controlPretty 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. 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.
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 selectedSimilarly, 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.
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:
In addition, there are four Boolean properties that control various aspects of the calendar. They are shown in Table 5-25.
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 StylesIn 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 ControlThe 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:
The following sections describe each of these in detail. 5.11.1.1 SelectionChanged eventThe 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 >" PrevMonthText="< 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.
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.
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 SelectedDateThe 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 >" PrevMonthText="< 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
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 selectionThe 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 >" PrevMonthText="< 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"> </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.
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 selection5.11.1.2 DayRender eventData 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: 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 >" PrevMonthText="< 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"> </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).
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 event5.11.1.3 VisibleMonthChanged eventThe 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 >" PrevMonthText="< 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"> </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:
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 |