#region Namespaces
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web;
using System.ComponentModel;
using System.Web.UI.HtmlControls;
using System.IO;
using System.Web.UI.Design;
using System.Collections;
using System.Text;
using System.Globalization;
// resolve ambiguous reference
using AttributeCollection = System.ComponentModel.AttributeCollection;
#endregion
namespace i386.UI
{
/// <summary>
/// Drop down date control which support date formatting and different cultures.
/// Author: Gavin Lyons, i386.com
/// Version: 0.2 - 18 May 2005.
///
/// --- You must leave this Summary section with the code.
/// </summary>
[DefaultProperty("Value")]
public class DropDownDateTime: System.Web.UI.Control, INamingContainer, IPostBackDataHandler
{
private string _Culture;
private bool _DebugMode=false;
//MM/dd/yyyy for US dd/MM/yyyy for UK, this make the default setting automatic "
private string _DateFormat=System.Threading.Thread.CurrentThread.CurrentCulture.DateTimeFormat.ShortDatePattern;
private string _MonthFormat = "MMMM";
private bool _SelectCurrentDate = true;
private bool _EnableSetDate=false;
private bool _TimeInput=false;
private int _YearsForward=0;
private int _YearsBack=0;
/// <summary>
/// Specifies a number of years from the current year. Value can also be negative
/// </summary>
[Bindable(true),
Description("Specifies how the month should be display MMM or MMMM"),
Category("Behavior"),
DefaultValue(null)]
public string MonthFormat
{
get {return _MonthFormat;}
set {_MonthFormat= value;}
}
public string Value
{
get
{
string s = (string)ViewState["Value"];
if(s == null) return String.Empty;
else return s;
}
set
{
this.SetSelected(value);
ViewState["Value"] = value;
}
}
/// <summary>
/// Show the hidden box with the DateTime value, also display Culture and DateFormat. Useful for Debuging purposes.
/// </summary>
public bool DebugMode
{
get {return _DebugMode;}
set {_DebugMode=value;}
}
/// <summary>
/// Displays a TimeInput box - THIS FEATURE IS NOT WORKING YET!
/// </summary>
[Bindable(true),
Description("TimeInput"),
Category("Behavior"),
DefaultValue(false)]
public bool TimeInput
{
get {return _TimeInput;}
set {_TimeInput=value;}
}
/// <summary>
/// Specifies a number of years from the current year. Value can also be negative
/// </summary>
[Bindable(true),
Description("Specifies a number of years from the current year. Value can also be negative"),
Category("Behavior"),
DefaultValue(0)]
public int YearsBack
{
get {return _YearsBack;}
set {_YearsBack = value;}
}
/// <summary>
/// Specifies a number of years from the current year. Value can also be negative
/// </summary>
[Bindable(true),
Description("Specifies a number of years from the current year. Value can also be negative"),
Category("Behavior"),
DefaultValue(0)]
public int YearsForward
{
get {return _YearsForward;}
set {_YearsForward= value;}
}
/// <summary>
/// Enables a checkbox to activate the date dropdownlists, if the checkbox is not set then the date is blank!!!
/// </summary>
[Bindable(true),
Description("Enables a checkbox to activate the date dropdownlists, if the checkbox is not set then the date is blank!!!"),
Category("Behavior"),
DefaultValue(false)]
public bool EnableSetDate
{
get {return _EnableSetDate;}
set {_EnableSetDate=value;}
}
/// <summary>
/// Specifies the date format output dd/MM/yyyy MM-dd-yyyy etc..
/// If this is not set then the server date format is taken.
/// Please note MMM ddd MMMM dddd are not valid!!
/// </summary>
[Bindable(true),
Description("Specifies the date format output dd/MM/yyyy MM-dd-yyyy etc.. If this is not set then the server date format is taken. Please note MMM ddd MMMM dddd are not valid!!"),
Category("Behavior"),
DefaultValue(-1)]
public string DateFormat
{
get {return _DateFormat;}
set {_DateFormat = value;}
}
/// <summary>
/// Specifies the date language, example en-GB for english, fr-FR for french etc..
/// If this is not set the server culture is taken.
/// </summary>
[Bindable(true),
Description("Specifies the date language, example en-GB for english, fr-FR for french etc.. If this is not set the server culture is taken."),
Category("Behavior"),
DefaultValue(-1)]
public string Culture
{
get {return _Culture;}
set {_Culture = value;}
}
public bool SelectCurrentDate
{
get {return _SelectCurrentDate;}
set {_SelectCurrentDate=value;}
}
#region ViewState Properties
private int SelectedDay
{
get
{
if(ViewState["SelectedDay"] == null)
return -1;
else
return (int)ViewState["SelectedDay"];
}
set
{
ViewState["SelectedDay"] = value;
}
}
private int SelectedMonth
{
get
{
if(ViewState["SelectedMonth"] == null)
return -1;
else
return (int)ViewState["SelectedMonth"];
}
set
{
ViewState["SelectedMonth"] = value;
}
}
private int SelectedYear
{
get
{
if(ViewState["SelectedYear"] == null)
return -1;
else
return (int)ViewState["SelectedYear"];
}
set
{
ViewState["SelectedYear"] = value;
}
}
private string SelectedTime
{
get
{
return (string)ViewState["SelectedTime"];
}
set
{
ViewState["SelectedTime"] = value;
}
}
private bool Checked
{
get
{
if(ViewState["Checked"] == null)
return false;
else
return (bool)ViewState["SelectedYear"];
}
set
{
ViewState["Checked"] = value;
}
}
#endregion
private static readonly object EventControlChanged = new object();
public event EventHandler Change;
public DropDownDateTime()
{
this.Load +=new EventHandler(DropDownDateTime_Load);
this.Init +=new EventHandler(DropDownDateTime_Init);
}
private void DropDownDateTime_Init(object sender, EventArgs e)
{
if(Page != null)
{
// Register the control with the page's postback mechanism, or
// the control will not update on Postback
Page.RegisterRequiresPostBack(this);
}
// if(this.DetermineRenderUplevel() && this.EnableClientScript)
// Use the EnableClientScript property to specify whether client-side validation is enabled.
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemWebUIWebControlsBaseValidatorClassEnableClientScriptTopic.asp
// The DetermineRenderUplevel method is a helper function used primarily by the RenderUplevel property to determine whether the client's browser supports uplevel rendering. For a browser to support uplevel rendering, it must support Internet Explorer Document Object Model (DOM) version 4 or later and ECMAScript version 1.2 or later.
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemwebuiwebcontrolsbasevalidatorclassdeterminerenderupleveltopic.asp
if (!Page.IsClientScriptBlockRegistered("DropDownDateTimeScript"))
{
// Might be an idea to put the Javascript Functions in the aspnet_client directory, so browsers could cache the JS functions.
// interesting URL http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnvs05/html/webresource.asp
#region Main Javascript Function
string JSCode= @"
// Author Gavin Lyons, i386.com
//function for returning how many days there are in a month including leap years
function DaysInMonth(WhichMonth, WhichYear)
{
var DaysInMonth = 31;
if (WhichMonth == 4 || WhichMonth == 6 || WhichMonth == 9 || WhichMonth == 11) DaysInMonth = 30;
if (WhichMonth == 2 && (WhichYear/4) != Math.floor(WhichYear/4)) DaysInMonth = 28;
if (WhichMonth == 2 && (WhichYear/4) == Math.floor(WhichYear/4)) DaysInMonth = 29;
return DaysInMonth;
}
//function to change the available days in a months
function ChangeOptionDays(Which, DateFormat)
{
if (document.getElementById) {
DaysObject = document.getElementById(Which + '_Day');
MonthObject = document.getElementById(Which + '_Month');
YearObject = document.getElementById(Which + '_Year');
TimeObject = document.getElementById(Which + '_Time');
CheckBoxObject= document.getElementById(Which + '_CheckBox');
DateBoxObject = document.getElementById(Which);
}
else if (document.layers) {
DaysObject = document.layers[Which + '_Day'];
MonthObject = document.layers[Which + '_Month'];
YearObject = document.layers[Which + '_Year'];
TimeObject = document.layers[Which + '_Time'];
CheckBoxObject= document.layers[Which + '_CheckBox'];
DateBoxObject = document.layers[Which];
}
else if (document.all) {
DaysObject = document.all[Which + '_Day'];
MonthObject = document.all[Which + '_Month'];
YearObject = document.all[Which + '_Year'];
TimeObject = document.all[Which + '_Time'];
CheckBoxObject= document.all[Which + '_CheckBox'];
DateBoxObject = document.all[Which];
}
Day= DaysObject[DaysObject.selectedIndex].text;
Month = MonthObject[MonthObject.selectedIndex].value;
Year = YearObject[YearObject.selectedIndex].text;
DaysForThisSelection = DaysInMonth(Month, Year);
CurrentDaysInSelection = DaysObject.length;
if (Day!='--' && Year!='--' && Month!='--' ) {
if (CurrentDaysInSelection > DaysForThisSelection)
{
for (i=0; i<(CurrentDaysInSelection-DaysForThisSelection); i++)
{
DaysObject.options[DaysObject.options.length - 1] = null;
}
}
if (DaysForThisSelection > CurrentDaysInSelection)
{
for (i=0; i<(DaysForThisSelection-CurrentDaysInSelection); i++)
{
NewOption = new Option(DaysObject.options.length + 1);
DaysObject.add(NewOption);
}
}
if (DaysObject.selectedIndex < 0) DaysObject.selectedIndex == 0;
DateBoxObject.value=formatDate(new Date(Year, (Month-1), Day), DateFormat);
if (CheckBoxObject)
{
if (CheckBoxObject.checked)
{
DaysObject.disabled=false;MonthObject.disabled=false;YearObject.disabled=false;
}
else
{
DaysObject.disabled=true;MonthObject.disabled=true;YearObject.disabled=true;DateBoxObject.value='';
}
}
} else {DateBoxObject.value=''}
}
// Date Convertion functions
function formatDate(vDate, vFormat){
var vDay = addZero(vDate.getDate());
var vMonth = addZero(vDate.getMonth()+1);
var vYearLong = addZero(vDate.getFullYear());
var vYearShort = addZero(vDate.getFullYear().toString().substring(3,4));
var vYear = (vFormat.indexOf('yyyy')>-1?vYearLong:vYearShort)
var vHour = addZero(vDate.getHours());
var vMinute = addZero(vDate.getMinutes());
var vSecond = addZero(vDate.getSeconds());
var vDateString = vFormat.replace(/dd/g, vDay).replace(/MM/g, vMonth).replace(/y{1,4}/g, vYear)
vDateString = vDateString.replace(/hh/g, vHour).replace(/mm/g, vMinute).replace(/ss/g, vSecond)
return vDateString
}
function addZero(vNumber){return ((vNumber < 10) ? '0' : '') + vNumber;}
";
#endregion
Page.RegisterClientScriptBlock("PickListScript", "<script language=\"javascript\" type=\"text/javascript\">" + JSCode + "</script>");
}
}
private void DropDownDateTime_Load(object sender, EventArgs e)
{
//Be sure child controls exist so they can be manipulated
EnsureChildControls();
}
protected override void CreateChildControls()
{
DateTime dt = DateTime.Today;
// Use CurrentDate if Value is empty and SelectCurrentDate is true.
if (SelectCurrentDate && this.Value=="")
{
// Use Current Date
SelectedDay = dt.Day;
SelectedMonth = dt.Month;
SelectedYear = dt.Year;
DateTimeFormatInfo formatInfo = new DateTimeFormatInfo();
formatInfo.FullDateTimePattern = DateFormat;
this.Value = dt.ToString(DateFormat,formatInfo);
}
// Days
DropDownList ddlboxDay = new DropDownList();
ddlboxDay.ID ="Day";
ddlboxDay.Attributes.Add("onchange","ChangeOptionDays('" + this.ClientID +"','" + DateFormat + "');");
for ( int nDay = 1; nDay<32; nDay++) ddlboxDay.Items.Add(nDay.ToString());
// So we can restore the Culture later
CultureInfo ExistingCulture = System.Threading.Thread.CurrentThread.CurrentCulture;
// Culture - changes language of months
if (Culture!=null) System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(Culture);
// Months
DropDownList ddlboxMonth = new DropDownList();
ddlboxMonth.ID ="Month";
ddlboxMonth.Attributes.Add("onchange","ChangeOptionDays('" + this.ClientID +"','" + DateFormat + "');");
for ( int nMonth=1; nMonth<=12; nMonth++)
{
DateTime MonthDate = new DateTime(2000,nMonth,1);
ddlboxMonth.Items.Add(new ListItem(MonthDate.ToString(this.MonthFormat),nMonth.ToString()));
}
// Years (Forward and Back properties)
DropDownList ddlboxYear = new DropDownList();
ddlboxYear.ID ="Year";
ddlboxYear.Attributes.Add("onchange","ChangeOptionDays('" + this.ClientID +"','" + DateFormat + "');");
ddlboxYear.ID ="Year";
if (YearsBack>=0)
{
for (int nYear = -YearsBack; nYear<=YearsForward; nYear++)
{
int ddlYear =dt.Year+nYear;
ddlboxYear.Items.Add(ddlYear.ToString());
}
}
else
{
for (int nYear = YearsForward; nYear<=-YearsBack; nYear++)
{
int ddlYear =dt.Year-nYear;
ddlboxYear.Items.Add(ddlYear.ToString());
}
}
// Select the DropDownList for the year
if (SelectedYear>0)
{
if (ddlboxYear.Items.FindByValue(SelectedYear.ToString())!=null) // See if the year is in the list.
{
ddlboxYear.Items.FindByValue(SelectedYear.ToString()).Selected = true;
}
}
if (SelectedMonth>0) ddlboxMonth.Items.FindByValue(SelectedMonth.ToString()).Selected = true;
if (SelectedDay>0) ddlboxDay.Items.FindByValue(SelectedDay.ToString()).Selected = true;
// Add Child Control
Controls.Add(ddlboxDay);
Controls.Add(ddlboxMonth);
Controls.Add(ddlboxYear);
// Time - Not Fully test or implemented yet!
if (TimeInput)
{
TextBox txtTime = new TextBox();
txtTime.Width = 60;
txtTime.Text = SelectedTime; // Set for ViewState Value.
txtTime.Attributes.Add("Size","8"); // Firefox support
txtTime.ID = "Time";
txtTime.Attributes.Add("onchange","ChangeOptionDays('" + this.ClientID +"','" + DateFormat + "');");
LiteralControl lc = new LiteralControl(" ");
Controls.Add(lc);
Controls.Add(txtTime);
}
if (EnableSetDate)
{ // Checkbox
CheckBox chkDate = new CheckBox();
chkDate.ID = "CheckBox";
chkDate.Checked = Checked;
chkDate.Attributes.Add("onclick","ChangeOptionDays('" + this.ClientID +"','" + DateFormat + "');");
Controls.Add(chkDate);
if (!Checked)
{
ddlboxYear.Enabled=false;
ddlboxMonth.Enabled=false;
ddlboxDay.Enabled=false;
//this.Value="";
}
else
{
ddlboxYear.Enabled=true;
ddlboxMonth.Enabled=true;
ddlboxDay.Enabled=true;
}
}
// Restore
System.Threading.Thread.CurrentThread.CurrentCulture = ExistingCulture;
}
protected virtual void OnChanged(EventArgs e)
{
EventHandler ControlChanged = (EventHandler)Events[EventControlChanged];
if(ControlChanged != null)
ControlChanged(this, e);
}
public event EventHandler Changed
{
add
{
Events.AddHandler(EventControlChanged, value);
}
remove
{
Events.RemoveHandler(EventControlChanged, value);
}
}
protected virtual void OnChange(EventArgs e)
{
if (Change != null)
// Raise event.
Change(this, e);
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
if (Page != null)
{
}
}
protected override void Render(HtmlTextWriter output)
{
if (DebugMode)
{
DateTimeFormatInfo formatInfo = new DateTimeFormatInfo();
output.Write("<input type=\"text\" name=\"" + this.ClientID + "\" id=\"" + this.ClientID + "\" value=\"" + this.Value + "\"><br/>" + DateFormat + " "
+ System.Threading.Thread.CurrentThread.CurrentCulture.DisplayName + "<br/>" +
Value + " MM " + SelectedMonth + " dd " + SelectedDay + " yyyy " + SelectedYear + " time " + SelectedTime + "<br/>");
}
else
{
output.Write("<input type=\"hidden\" name=\"" + this.ClientID + "\" id=\"" + this.ClientID + "\" value=\"" + this.Value + "\">");
}
EnsureChildControls();
base.Render(output);
}
// Override RaisePostDataChangedEvent method.
void IPostBackDataHandler.RaisePostDataChangedEvent()
{
// Call the event method. This is optional.
OnChange(EventArgs.Empty);
}
bool IPostBackDataHandler.LoadPostData(string postDataKey,
System.Collections.Specialized.NameValueCollection postCollection)
{
int Day = 0;
int Month = 0;
int Year = 0;
string Time = "";
bool Changed = false;
// Updates the Day Viewstate value
if(postCollection[this.UniqueID.ToString() + ":Day"] != "")
{
Day = Int32.Parse(postCollection[this.UniqueID.ToString() + ":Day"]);
if (Day != this.SelectedDay)
{
this.SelectedDay = Day;
Changed = true;
}
}
else
{ // Probably don't need this bit
if(this.SelectedDay != -1)
{
this.SelectedDay = -1;
Changed = true;
}
}
// Updates the Month Viewstate value
if(postCollection[this.UniqueID.ToString() + ":Month"] != "")
{
Month = Int32.Parse(postCollection[this.UniqueID.ToString() + ":Month"]);
if (Month != this.SelectedMonth)
{
this.SelectedMonth = Month;
Changed = true;
}
}
else
{ // Probably don't need this bit
if(this.SelectedMonth != -1)
{
this.SelectedMonth = -1;
Changed = true;
}
}
// Updates the Year Viewstate value
if(postCollection[this.UniqueID.ToString() + ":Year"] != "")
{
Year = Int32.Parse(postCollection[this.UniqueID.ToString() + ":Year"]);
if (Year != this.SelectedYear)
{
this.SelectedYear = Year;
Changed = true;
}
}
else
{
if(this.SelectedYear != -1)
{
this.SelectedYear = -1;
Changed = true;
}
}
// Updates the Time Viewstate value *** Implemented yet!
if(postCollection[this.UniqueID.ToString() + ":Time"] != "")
{
Time = postCollection[this.UniqueID.ToString() + ":Time"];
if (Time != this.SelectedTime )
{
this.SelectedTime = Time ;
Changed = true;
}
}
// Checkbox
/*
if(postCollection[this.UniqueID.ToString() + ":Checkbox"] != "")
{
Year = bool.Parse(postCollection[this.UniqueID.ToString() + ":Year"]);
if (Year != this.SelectedYear)
{
this.SelectedYear = Year;
Changed = true;
}
}
*/
if(this.SelectedDay == -1 && this.SelectedMonth == -1 && this.SelectedYear == -1)
this.Value = "";
else
{
// Build a DateTime string based on the DateFormat
DateTimeFormatInfo formatInfo = new DateTimeFormatInfo();
formatInfo.FullDateTimePattern = DateFormat;
DateTime dt = new DateTime(this.SelectedYear, this.SelectedMonth, this.SelectedDay);
this.Value = dt.ToString(DateFormat,formatInfo);
}
return Changed;
}
private void SetSelected(string StoredValue)
{
DateTimeFormatInfo formatInfo = new DateTimeFormatInfo();
formatInfo.FullDateTimePattern = DateFormat;
DateTime dt = DateTime.ParseExact(StoredValue,DateFormat,formatInfo);
SelectedDay = dt.Day;
SelectedMonth = dt.Month;
SelectedYear = dt.Year;
}
}
}