I stepped by this page:
http://www.filamentgroup.com/lab/date_range_picker_using_jquery_ui_16_and_jquery_ui_css_framework/ and let me tell you,this is one of the best and coolest daterangepicker in the web in my opinion,they did a great job with extending the original jQuery UI DatePicker.Of course I made enhancements to the original plugin (fixed few bugs) and added a new option (Clear) to clear the textbox.
In this article I well use that updated plugin and show you how to use it in asp.net..you will definitely like it.
So,What do I need?
1- jQuery library : you can use 1.3.2 or 1.4.2 which is the latest version so far,in my article I will use the latest version.
2- jQuery UI library (1.8): As I mentioned earlier,daterangepicker plugin is based on the original jQuery UI DatePicker so that library should be included into your page.
3- jQuery DateRangePicker plugin : you can go to the author page or use the modified one (it's included in the attachment),in this article I will use the modified one.
4- Visual Studio 2005 or later : very funny :D[as if you don't already knows that],anyway in my article I will use VS 2008.
Note: in the attachment,I included all CSS and JS files so don't worry.
How to use it?
Then add this html:
First Date:
Second Date:
As you can see,it includes TextBox1 which we are going to attach the daterangepicker to it,2 labels to show you later on by code on how to read the date from the textbox and set it to the labels
Now we have to attach the daterangepicker to the textbox by using jQuery (Note:visit the author's website for more info on daterangerpicker's options and how to use them):
Finally,add this C# code:
protected void SubmitButton_Click(object sender, EventArgs e)
{
if (TextBox1.Text.Trim().Length == 0)
{
return;
}
string selectedDate = TextBox1.Text;
if (selectedDate.Contains("-"))
{
DateTime startDate;
DateTime endDate;
string[] splittedDates = selectedDate.Split("-".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
if (splittedDates.Count() == 2 && DateTime.TryParse(splittedDates[0], out startDate) && DateTime.TryParse(splittedDates[1], out endDate))
{
FirstDate.Text = startDate.ToShortDateString();
SecondDate.Text = endDate.ToShortDateString();
}
else
{
//maybe the client has modified/altered the input i.e. hacking tools
}
}
else
{
DateTime selectedDateObj;
if (DateTime.TryParse(selectedDate, out selectedDateObj))
{
FirstDate.Text = selectedDateObj.ToShortDateString();
SecondDate.Text = string.Empty;
}
else
{
//maybe the client has modified/altered the input i.e. hacking tools
}
}
}
This is the way on how to read from the textbox,
That's it!.
FAQ:
1-Why did you add this style?:
A:For two reasons:
- To show the Daterangepicker in a smaller size because it's original size is huge.
- To show you how to control the size of it.
2- Can I change the theme?
A: yes you can,you will notice that I'm using Redmond theme which you will find it in jQuery UI website,visit their website and download a different theme,you may also have to make modifications to the css of daterangepicker,it's all yours.
3- Why did you add a font size to the textbox?
A: To make the design look better,try to remove it and see by your self.
4- Can I register the script at codebehind?
A: yes you can
5- Why do I need to set attributes (readonly) and (unselectable) for the textbox ?
A:readonly will make the textbox not editable by the user,unselectable will block the blinking typing cursor from appearing if the user clicked on the textbox,you will notice that both attributes are necessary to be used together,you can't just use one of them...for logical reasons of course.
Finally,I hope everyone liked the article and as always,your feedbacks are always welcomed and if anyone have any suggestions or made any modifications that might be useful for anyone else then please post it here and at at the author's website.
P.S : There is no harm in posting comments
Hi everyone,
First of all,this is my first article so if you have any suggestions or comments on my article please post it.
Introduction:
Many of us created a group options using "select" like this :
Which will be rendered like this:
as you can see it's pretty easy to do it using select tag,you can refer to this W3C site for more information on this tag.
so if you use this optgroup,then you will be able to create a group for your items,it's the key for our answer.
Cool,but is it possible to do it in ASP.NET dropdownlist ?
Since many of us want to use binding and handle items at server side and do other stuff ,it will be great if we can add grouping feature to the dropdownlist and the answer is Yes it's possible and this is what I'm going to discuss in this article.
How to do it in ASP.NET DropDownList:
Asp.net dropdownlist doesn't support grouping by default,however we can implement this feature by overriding the functionality/rending of the dropdownlist. Here are the steps:
1) Create a new project of type ClassLibrary and name it ("GroupDropDownList")
2) Rename the class name from Class1.cs to GroupDropDownList.cs
3) Right-click on your solution then choose "Add Reference" then from ".Net" tab choose System.Web then press OK.
3) Replace GroupDropDownList.cs code with this:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Collections;
namespace GroupDropDownList
{
/// <summary>
/// Summary description for GroupDropDownList.
/// </summary>
[ToolboxData("<{0}:GroupDropDownList runat=server></{0}:GroupDropDownList>")]
public class GroupDropDownList : System.Web.UI.WebControls.DropDownList
{
/// <summary>
/// The field in the datasource which provides values for groups
/// </summary>
[DefaultValue(""), Category("Data")]
public virtual string DataGroupField
{
get
{
object obj = this.ViewState["DataGroupField"];
if (obj != null)
{
return (string)obj;
}
return string.Empty;
}
set
{
this.ViewState["DataGroupField"] = value;
}
}
/// <summary>
/// if a group doesn't has any enabled items,there is no need
/// to render the group too
/// </summary>
/// <param name="groupName"></param>
/// <returns></returns>
private bool IsGroupHasEnabledItems(string groupName)
{
ListItemCollection items = this.Items;
ListItem item;
for (int i = 0; i < items.Count; i++)
{
item = items[i];
if (item.Attributes["DataGroupField"].Equals(groupName) && item.Enabled)
{
return true;
}
}
return false;
}
/// <summary>
/// Render this control to the output parameter specified.
/// Based on the source code of the original DropDownList method
/// </summary>
/// <param name="output"> The HTML writer to write out to </param>
protected override void RenderContents(HtmlTextWriter writer)
{
ListItemCollection items = this.Items;
int itemCount = this.Items.Count;
string curGroup = String.Empty;
string itemGroup;
bool bSelected = false;
if (itemCount <= 0)
{
return;
}
for (int i = 0; i < itemCount; i++)
{
ListItem item = items[i];
itemGroup = (string)item.Attributes["DataGroupField"];
if (itemGroup != null && itemGroup != curGroup && IsGroupHasEnabledItems(itemGroup))
{
if (curGroup != String.Empty)
{
writer.WriteEndTag("optgroup");
writer.WriteLine();
}
curGroup = itemGroup;
writer.WriteBeginTag("optgroup");
writer.WriteAttribute("label", curGroup, true);
writer.Write('>');
writer.WriteLine();
}
// we don't want to render disabled items
if (item.Enabled)
{
writer.WriteBeginTag("option");
if (item.Selected)
{
if (bSelected)
{
throw new HttpException("Cant_Multiselect_In_DropDownList");
}
bSelected = true;
writer.WriteAttribute("selected", "selected", false);
}
writer.WriteAttribute("value", item.Value, true);
writer.Write('>');
HttpUtility.HtmlEncode(item.Text, writer);
writer.WriteEndTag("option");
writer.WriteLine();
}
}
if (curGroup != String.Empty)
{
writer.WriteEndTag("optgroup");
writer.WriteLine();
}
}
/// <summary>
/// Perform data binding logic that is associated with the control
/// </summary>
/// <param name="e">An EventArgs object that contains the event data</param>
protected override void OnDataBinding(EventArgs e)
{
// Call base method to bind data
base.OnDataBinding(e);
if (this.DataGroupField == String.Empty)
{
return;
}
// For each Item add the attribute "DataGroupField" with value from the datasource
IEnumerable dataSource = GetResolvedDataSource(this.DataSource, this.DataMember);
if (dataSource != null)
{
ListItemCollection items = this.Items;
int i = 0;
string groupField = this.DataGroupField;
foreach (object obj in dataSource)
{
string groupFieldValue = DataBinder.GetPropertyValue(obj, groupField, null);
ListItem item = items[i];
item.Attributes.Add("DataGroupField", groupFieldValue);
i++;
}
}
}
/// <summary>
/// This is copy of the internal ListControl method
/// </summary>
/// <param name="dataSource"></param>
/// <param name="dataMember"></param>
/// <returns></returns>
private IEnumerable GetResolvedDataSource(object dataSource, string dataMember)
{
if (dataSource != null)
{
IListSource source1 = dataSource as IListSource;
if (source1 != null)
{
IList list1 = source1.GetList();
if (!source1.ContainsListCollection)
{
return list1;
}
if ((list1 != null) && (list1 is ITypedList))
{
ITypedList list2 = (ITypedList)list1;
PropertyDescriptorCollection collection1 = list2.GetItemProperties(new PropertyDescriptor[0]);
if ((collection1 == null) || (collection1.Count == 0))
{
throw new HttpException("ListSource_Without_DataMembers");
}
PropertyDescriptor descriptor1 = null;
if ((dataMember == null) || (dataMember.Length == 0))
{
descriptor1 = collection1[0];
}
else
{
descriptor1 = collection1.Find(dataMember, true);
}
if (descriptor1 != null)
{
object obj1 = list1[0];
object obj2 = descriptor1.GetValue(obj1);
if ((obj2 != null) && (obj2 is IEnumerable))
{
return (IEnumerable)obj2;
}
}
throw new HttpException("ListSource_Missing_DataMember");
}
}
if (dataSource is IEnumerable)
{
return (IEnumerable)dataSource;
}
}
return null;
}
#region Internal behaviour
/// Saves the state of the view.
/// </summary>
protected override object SaveViewState()
{
// Create an object array with one element for the CheckBoxList's
// ViewState contents, and one element for each ListItem in skmCheckBoxList
object[] state = new object[this.Items.Count + 1];
object baseState = base.SaveViewState();
state[0] = baseState;
// Now, see if we even need to save the view state
bool itemHasAttributes = false;
for (int i = 0; i < this.Items.Count; i++)
{
if (this.Items[i].Attributes.Count > 0)
{
itemHasAttributes = true;
// Create an array of the item's Attribute's keys and values
object[] attribKV = new object[this.Items[i].Attributes.Count * 2];
int k = 0;
foreach (string key in this.Items[i].Attributes.Keys)
{
attribKV[k++] = key;
attribKV[k++] = this.Items[i].Attributes[key];
}
state[i + 1] = attribKV;
}
}
// return either baseState or state, depending on whether or not
// any ListItems had attributes
if (itemHasAttributes)
return state;
else
return baseState;
}
/// <summary>
/// Loads the state of the view.
/// </summary>
/// <param name="savedState">State of the saved.</param>
protected override void LoadViewState(object savedState)
{
if (savedState == null) return;
// see if savedState is an object or object array
if (savedState is object[])
{
// we have an array of items with attributes
object[] state = (object[])savedState;
base.LoadViewState(state[0]); // load the base state
for (int i = 1; i < state.Length; i++)
{
if (state[i] != null)
{
// Load back in the attributes
object[] attribKV = (object[])state[i];
for (int k = 0; k < attribKV.Length; k += 2)
this.Items[i - 1].Attributes.Add(attribKV[k].ToString(),
attribKV[k + 1].ToString());
}
}
}
else
// we have just the base state
base.LoadViewState(savedState);
}
#endregion
}
}
4) Rebuild the solution.
5) Open the solution that has your website
6) In the toolbox,right-click then choose "Add tab",then write the name of the tab...let's name it "Group DropDownList"
7) Right-click on that tab then select "choose items",then from ".Net FrameWork Components" click "Browse",then point to the dll that was created by our class library..it's name is "GroupDropDownList.dll".then click OK,then OK for the other dialog,you will notice that our group dropdownlist control has been added to the toolbox
8) drag-n-drop
How to use it:
let's assume that this is our data:
Country_id Country_Name Country_Title
1 JORDAN Middle East Countries
2 Saudi Arabia Middle East Countries
3 Sudan Africa Countries
and let's assume that you have a groupdropdownlist called ddlCountries,then you have to bind it but I want to warn you that the data must be sorted by DataGroupField before binding it:
DataView myview = yourDataTable.DefaultView;
myview.Sort = "Country_Title asc";
ddlProcessType.DataSource = myview;
ddlProcessType.DataTextField = "Country_Name";
ddlProcessType.DataValueField = "Country_ID";
ddlProcessType.DataGroupField = "Country_Title";
ddlProcessType.DataBind();
DataGoupField must contains the name of the column that it will be used as a Title to any group
so the data in the groupDropDownList will show your data like this:
Middle East Countries
Jordan
Saudi Arabia
Africa Countries
Sudan
Pretty cool code but wait a second ?! Explain to me the code in our class library:
A) What is DataGroupField ? :
we created a property and named it "DataGroupField" (yeah,I tried to name it something similar to those DataTextField and DataValueField to make it more appropriate) and make it appears as a property in group "Data",but I needed to store it's value in a viewstate so that I will not lose it in postbacks,and it's value by default is empty string.
B) What does IsGroupHasEnabledItems do ? :
You may want to disable some items and that's fine,however if you disabled all items of a group then you don't want to render that Title of the group at all,so the main purpose of this method is to check if that group still has any enabled items or not
C) Why did we overrided RenderContents ? :
We need to override how our control is rendered,as you remember we need grouping so we need to customize how our control is rendered to achive the same results we achieved in our sample of "select" tag.
please read my comments in that method
D:) Why did we overrided OnDataBinding ? :
This function is called on binding before calling RenderContent,but in RenderContent I will never know the current item's group which it's going to be rendered,so that's gave me an idea..I can loop within my items and check if that property (DataGroupField) is not empty then you need grouping,but I need to store an attribute on the item so I can read from it later on in RenderContents method to know to which group is that item..tricky right
E:) What does that GetResolvedDataSource do ? :
Just to check if the datasource is valid or not
F:) Why did we overrided SaveViewState and LoadViewState ? :
When the control postback or refreshed,control will be rendered once again but without binding(without calling OnDataBinding),which means that our items will be with no attributes(if you remember,OnDataBinding is the one who adds the attribute DataGroupField which later on is used in RenderContents method and used to define item's group) and thus the grouping will not be rendered.
so what's the solution? we need to override how control's viewstate is saved and retrieved,WHY? because we want to store the attribute into viewstate and load it once again,that way when the control is rendered,our items will keep it's attribute within it's viewstate and thus the grouping will be rendered..do you find it tricky?
FAQ:
1) I'm using DataReader,not DataTable so what should I do?
You need to fill your data from the datareader into a temporary datatable,you can do it like in this example:
DataTable table1 = new DataTable();
table1.Columns.Add("Country_ID");
table1.Columns.Add("Country_Name");
table1.Columns.Add("Country_Title");
while (yourdatareader.Read())
{
DataRow mydatarow = table1.NewRow();
mydatarow["Country_Title"] = yourdatareader["Country_Title"].ToString();
mydatarow["Country_Name"] = yourdatareader["Country_Name"].ToString();
mydatarow["Country_ID"] = yourdatareader["Country_ID"].ToString();
table1.Rows.Add(mydatarow);
}
DataView myview = table1.DefaultView;
myview.Sort = "Country_Title asc";
ddlProcessType.DataSource = myview;
ddlProcessType.DataTextField = "Country_Name";
ddlProcessType.DataValueField = "Country_ID";
ddlProcessType.DataGroupField = "Country_Title";
ddlProcessType.DataBind();
2) What if I want to add an item within a group,can I do that?
Do it like this:
ListItem egypt = new ListItem("Egypt", "4");
egypt.Attributes.Add("DataGroupField", "Africa Countries");
GroupDropDownList1.Items.Add(egypt);
Credits:
I want to thank Scott Mitchell for his great article "ListControl Items, Attributes, and ViewState" and I give him the creadit for using his code "LoadViewState and SaveViewState".
Also I want to thank lotuspro for his ideas in his article "ASP.NET DropDownList with OptionGroup support"