/* System.Web.UI.HtmlControls
* Authors
* Leen Toelen (toelen@hotmail.com)
*/
using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.Util;
using System.Globalization;
using System.ComponentModel;
using System.Collections;
using System.Collections.Specialized;
namespace System.Web.UI.HtmlControls{
[ControlBuilder (typeof (HtmlSelectBuilder))]
[DefaultEvent("ServerChange")]
[ValidationProperty("Value")]
public class HtmlSelect : HtmlContainerControl, IPostBackDataHandler{
private int _cachedSelectedIndex;
private object _dataSource;
private static readonly object EventServerChange = new object ();
private ListItemCollection _items;
public HtmlSelect():base("select"){
_cachedSelectedIndex = -1;
}
protected override void AddParsedSubObject(object obj){
if (obj as ListItem != null) {
this.Items.Add((ListItem) obj);
return;
}
throw new HttpException("HtmlSelect cannot have children of Type " + obj.GetType().Name);
}
protected virtual void ClearSelection()
{
foreach (ListItem item in Items)
item.Selected = false;
}
protected override ControlCollection CreateControlCollection(){
return new EmptyControlCollection(this);
}
protected override void LoadViewState(object savedState)
{
if (savedState != null) {
Triplet state = (Triplet) savedState;
base.LoadViewState (state.First);
Items.LoadViewState (state.Second);
object indices = state.Third;
if (indices != null) {
Select ((int []) indices);
}
}
}
protected override void OnDataBinding (EventArgs e)
{
base.OnDataBinding (e);
IEnumerable resolvedDataSource = DataSourceHelper.GetResolvedDataSource (DataSource, DataMember);
if (resolvedDataSource != null) {
string text = DataTextField;
string value = DataValueField;
Items.Clear();
ICollection rdsCollection = resolvedDataSource as ICollection;
if (rdsCollection != null)
Items.Capacity = rdsCollection.Count;
bool valid = false;
if (text.Length > 0 && value.Length > 0)
valid = true;
foreach (object current in resolvedDataSource) {
ListItem li = new ListItem ();
if (valid == true){
if (text.Length > 0)
li.Text = DataBinder.GetPropertyValue (current, text, null);
if (value.Length > 0)
li.Value = DataBinder.GetPropertyValue (current, value, null);
} else {
li.Value = li.Text = current.ToString();
}
Items.Add (li);
}
}
if (_cachedSelectedIndex != -1) {
SelectedIndex = _cachedSelectedIndex;
_cachedSelectedIndex = -1;
}
}
protected override void OnPreRender(EventArgs e){
if (Page != null && Size >= 0 && !Disabled){
Page.RegisterRequiresPostBack(this);
}
}
protected virtual void OnServerChange(EventArgs e){
EventHandler handler = (EventHandler) Events[EventServerChange];
if (handler != null)
handler (this,e);
}
protected override void RenderAttributes(HtmlTextWriter writer){
writer.WriteAttribute("name", Name);
Attributes.Remove("name");
Attributes.Remove("DataValueField");
Attributes.Remove("DataTextField");
Attributes.Remove("DataMember");
base.RenderAttributes(writer);
}
protected override void RenderChildren(HtmlTextWriter writer){
//flush output
writer.WriteLine();
// increase indent level, improves readability
writer.Indent = writer.Indent + 1;
if (Items.Count >= 0){
// display all options, and set the selected option
bool rendered_selected = false;
foreach (ListItem option in Items){
//write begin tag with attributes
writer.WriteBeginTag("option");
if (!rendered_selected && option.Selected){
writer.WriteAttribute("selected","selected");
if (!Multiple)
rendered_selected = true;
}
else if (option.Selected){
option.Selected = false;
}
writer.WriteAttribute("value",option.Value,true);
option.Attributes.Remove("text");
option.Attributes.Remove("value");
option.Attributes.Remove("selected");
option.Attributes.Render(writer);
writer.Write('>');
//write the option text
HttpUtility.HtmlEncode(option.Text, writer);
//close the current option tag
writer.WriteEndTag("option");
//flush output
writer.WriteLine();
}
}
// set the indent level back to normal
writer.Indent = writer.Indent - 1;
}
protected override object SaveViewState ()
{
object baseViewState = base.SaveViewState ();
object itemsViewState = Items.SaveViewState ();
object indices = null;
if (Events[EventServerChange] != null || !Disabled || Visible)
indices = SelectedIndices;
if (indices != null || baseViewState != null || itemsViewState != null)
return new Triplet (baseViewState, itemsViewState, indices);
return null;
}
protected virtual void Select(int[] selectedIndices){
// unselect all options
ClearSelection();
// iterate through options, and set when selected
foreach (int current in selectedIndices){
if (current >= 0 && current < Items.Count){
Items[current].Selected = true;
}
}
}
bool IPostBackDataHandler.LoadPostData (string postDataKey,
NameValueCollection postCollection)
{
//get the posted selectedIndices[]
string [] postedValueColl = postCollection.GetValues(postDataKey);
bool changed = false;
if (postedValueColl != null){
if (!Multiple){
//single selection
//int postedValue = Items.FindIndexByValue(postedValueColl[0]);
int postedValue = Items.IndexOf(Items.FindByValue(postedValueColl[0]));
if (postedValue != SelectedIndex){
//set the SelectedIndex
SelectedIndex = postedValue;
changed = true;
}
}
else{
//multiple selection
int postedValueCount = postedValueColl.Length;
int[] arr= new int[postedValueCount];
//fill an array with the posted Values
for (int i = 0; i < postedValueCount; i++)
arr[i] = Items.IndexOf(Items.FindByValue(postedValueColl[i]));
//test if everything went fine
if( postedValueCount == SelectedIndices.Length){
for (int i = 0; i < postedValueCount; i++)
if(arr[i] != SelectedIndices[i])
changed = true;
}
else
changed = true;
//commit the posted Values
if(changed)
Select(arr);
}
}
else if (SelectedIndex != -1){
SelectedIndex = -1;
changed = true;
}
return changed;
}
void IPostBackDataHandler.RaisePostDataChangedEvent ()
{
OnServerChange (EventArgs.Empty);
}
//starts tracking changes to the viewstate
protected override void TrackViewState(){
base.TrackViewState();
Items.TrackViewState();
}
[WebCategory("Action")]
[WebSysDescription("Fires when the selection changes.")]
public event EventHandler ServerChange{
add{
Events.AddHandler(EventServerChange, value);
}
remove{
Events.RemoveHandler(EventServerChange, value);
}
}
[DefaultValue("")]
[WebCategory("Data")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[WebSysDescription("The data member of the select.")]
public virtual string DataMember{
get{
object viewStateDataMember = ViewState["DataMember"];
if ( viewStateDataMember != null) return (String) viewStateDataMember;
return String.Empty;
}
set{
Attributes["DataMember"] = HtmlControl.AttributeToString(value);
}
}
[DefaultValue(null)]
[WebCategory("Data")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[WebSysDescription("The data source used to populate the list with data.")]
public virtual object DataSource{
get{
return _dataSource;
}
set{
if (value != null && !(value is IListSource)) {
if (!(value is IEnumerable))
throw new ArgumentException ("Invalid dataSource type");
}
_dataSource = value;
}
}
[DefaultValue("")]
[WebCategory("Data")]
[WebSysDescription("The field in the data source that provides the item value.")]
public virtual string DataTextField{
get{
string attr = Attributes["DataTextField"];
if (attr != null){
return attr;
}
return String.Empty;
}
set{
Attributes["DataTextField"] = AttributeToString(value);
}
}
[DefaultValue("")]
[WebCategory("Data")]
[WebSysDescription("The field in the data source that provides the item value.")]
public virtual string DataValueField{
get{
string attr = Attributes["DataValueField"];
if (attr != null)return attr;
return String.Empty;
}
set{
Attributes["DataValueField"] = AttributeToString(value);
}
}
public override string InnerHtml{
get{
throw new NotSupportedException("InnerHtml is not supported by " + this.GetType().Name);
}
set{
throw new NotSupportedException("InnerHtml is not supported by " + this.GetType().Name);
}
}
public override string InnerText{
get{
throw new NotSupportedException("InnerText is not supported by " + this.GetType().Name);
}
set{
throw new NotSupportedException("InnerText is not supported by " + this.GetType().Name);
}
}
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public ListItemCollection Items{
get{
if (_items == null){
_items = new ListItemCollection();
if (IsTrackingViewState) _items.TrackViewState();
}
return _items;
}
}
[DefaultValue("")]
[WebCategory("Behavior")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public bool Multiple{
get{
string attr = Attributes["multiple"];
if (attr != null) return (0 == String.Compare (attr, "true", true));
return false;
}
set{
Attributes["multiple"] = value.ToString ();
}
}
[DefaultValue("")]
[WebCategory("Behavior")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public string Name{
get{
return UniqueID;
}
set{
//LAMESPEC
return;
}
}
[HtmlControlPersistable (false)]
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public virtual int SelectedIndex {
get{
for (int i=0; i 0) Items[0].Selected = true;
return 0;
}
return -1;
}
set{
if(Items.Count == 0){
_cachedSelectedIndex = value;
return;
}
if (value < -1 || value >= Items.Count)
throw new ArgumentOutOfRangeException();
ClearSelection();
if (value >= 0)
Items[value].Selected = true;
}
}
protected virtual int[] SelectedIndices {
get{
int[] indices = new int[3];
int indicesCount = 0;
for(int i=0; i < Items.Count; i++){
if (Items[i].Selected){
if( indicesCount == (int) indices.Length){
int[] temp = new int[indicesCount + indicesCount];
indices.CopyTo(temp,0);
indices = temp;
}
indices[indicesCount] = i;
indicesCount++;
}
}
int[] arr = new int[indicesCount];
System.Array.Copy(indices,0,arr,0,indicesCount);
return arr;
}
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public int Size{
get{
string attr = Attributes["size"];
if (attr != null){
return Int32.Parse(attr, CultureInfo.InvariantCulture);
}
return -1;
}
set{
Attributes["size"] = AttributeToString(value);
}
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public string Value {
get{
int selectedIndex = SelectedIndex;
if (selectedIndex >=0 && selectedIndex < Items.Count){
return Items[selectedIndex].Value;
}
return String.Empty;
}
set{
int findValue = Items.IndexOf(Items.FindByValue(value));
if (findValue >= 0) SelectedIndex = findValue;
}
}
} // class HtmlSelect
} // namespace System.Web.UI.HtmlControls