HtmlSelect.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. /* System.Web.UI.HtmlControls
  2. * Authors
  3. * Leen Toelen ([email protected])
  4. */
  5. using System;
  6. using System.Web;
  7. using System.Web.UI;
  8. using System.Web.UI.WebControls;
  9. using System.Web.Util;
  10. using System.Globalization;
  11. using System.ComponentModel;
  12. using System.Collections;
  13. using System.Collections.Specialized;
  14. namespace System.Web.UI.HtmlControls{
  15. [ControlBuilder (typeof (HtmlSelectBuilder))]
  16. [DefaultEvent("ServerChange")]
  17. [ValidationProperty("Value")]
  18. public class HtmlSelect : HtmlContainerControl, IPostBackDataHandler{
  19. private int _cachedSelectedIndex;
  20. private object _dataSource;
  21. private static readonly object EventServerChange = new object ();
  22. private ListItemCollection _items;
  23. public HtmlSelect():base("select"){
  24. _cachedSelectedIndex = -1;
  25. }
  26. protected override void AddParsedSubObject(object obj){
  27. if (obj as ListItem != null) {
  28. this.Items.Add((ListItem) obj);
  29. return;
  30. }
  31. throw new HttpException("HtmlSelect cannot have children of Type " + obj.GetType().Name);
  32. }
  33. protected virtual void ClearSelection()
  34. {
  35. foreach (ListItem item in Items)
  36. item.Selected = false;
  37. }
  38. protected override ControlCollection CreateControlCollection(){
  39. return new EmptyControlCollection(this);
  40. }
  41. protected override void LoadViewState(object savedState)
  42. {
  43. if (savedState != null) {
  44. Triplet state = (Triplet) savedState;
  45. base.LoadViewState (state.First);
  46. Items.LoadViewState (state.Second);
  47. object indices = state.Third;
  48. if (indices != null) {
  49. Select ((int []) indices);
  50. }
  51. }
  52. }
  53. protected override void OnDataBinding (EventArgs e)
  54. {
  55. base.OnDataBinding (e);
  56. IEnumerable resolvedDataSource = DataSourceHelper.GetResolvedDataSource (DataSource, DataMember);
  57. if (resolvedDataSource != null) {
  58. string text = DataTextField;
  59. string value = DataValueField;
  60. Items.Clear();
  61. ICollection rdsCollection = resolvedDataSource as ICollection;
  62. if (rdsCollection != null)
  63. Items.Capacity = rdsCollection.Count;
  64. bool valid = false;
  65. if (text.Length > 0 && value.Length > 0)
  66. valid = true;
  67. foreach (object current in resolvedDataSource) {
  68. ListItem li = new ListItem ();
  69. if (valid == true){
  70. if (text.Length > 0)
  71. li.Text = DataBinder.GetPropertyValue (current, text, null);
  72. if (value.Length > 0)
  73. li.Value = DataBinder.GetPropertyValue (current, value, null);
  74. } else {
  75. li.Value = li.Text = current.ToString();
  76. }
  77. Items.Add (li);
  78. }
  79. }
  80. if (_cachedSelectedIndex != -1) {
  81. SelectedIndex = _cachedSelectedIndex;
  82. _cachedSelectedIndex = -1;
  83. }
  84. }
  85. protected override void OnPreRender(EventArgs e){
  86. if (Page != null && Size >= 0 && !Disabled){
  87. Page.RegisterRequiresPostBack(this);
  88. }
  89. }
  90. protected virtual void OnServerChange(EventArgs e){
  91. EventHandler handler = (EventHandler) Events[EventServerChange];
  92. if (handler != null)
  93. handler (this,e);
  94. }
  95. protected override void RenderAttributes(HtmlTextWriter writer){
  96. writer.WriteAttribute("name", Name);
  97. Attributes.Remove("name");
  98. Attributes.Remove("DataValueField");
  99. Attributes.Remove("DataTextField");
  100. Attributes.Remove("DataMember");
  101. base.RenderAttributes(writer);
  102. }
  103. protected override void RenderChildren(HtmlTextWriter writer){
  104. //flush output
  105. writer.WriteLine();
  106. // increase indent level, improves readability
  107. writer.Indent = writer.Indent + 1;
  108. if (Items.Count >= 0){
  109. // display all options, and set the selected option
  110. bool rendered_selected = false;
  111. foreach (ListItem option in Items){
  112. //write begin tag with attributes
  113. writer.WriteBeginTag("option");
  114. if (!rendered_selected && option.Selected){
  115. writer.WriteAttribute("selected","selected");
  116. if (!Multiple)
  117. rendered_selected = true;
  118. }
  119. else if (option.Selected){
  120. option.Selected = false;
  121. }
  122. writer.WriteAttribute("value",option.Value,true);
  123. option.Attributes.Remove("text");
  124. option.Attributes.Remove("value");
  125. option.Attributes.Remove("selected");
  126. option.Attributes.Render(writer);
  127. writer.Write('>');
  128. //write the option text
  129. HttpUtility.HtmlEncode(option.Text, writer);
  130. //close the current option tag
  131. writer.WriteEndTag("option");
  132. //flush output
  133. writer.WriteLine();
  134. }
  135. }
  136. // set the indent level back to normal
  137. writer.Indent = writer.Indent - 1;
  138. }
  139. protected override object SaveViewState ()
  140. {
  141. object baseViewState = base.SaveViewState ();
  142. object itemsViewState = Items.SaveViewState ();
  143. object indices = null;
  144. if (Events[EventServerChange] != null || !Disabled || Visible)
  145. indices = SelectedIndices;
  146. if (indices != null || baseViewState != null || itemsViewState != null)
  147. return new Triplet (baseViewState, itemsViewState, indices);
  148. return null;
  149. }
  150. protected virtual void Select(int[] selectedIndices){
  151. // unselect all options
  152. ClearSelection();
  153. // iterate through options, and set when selected
  154. foreach (int current in selectedIndices){
  155. if (current >= 0 && current < Items.Count){
  156. Items[current].Selected = true;
  157. }
  158. }
  159. }
  160. bool IPostBackDataHandler.LoadPostData (string postDataKey,
  161. NameValueCollection postCollection)
  162. {
  163. //get the posted selectedIndices[]
  164. string [] postedValueColl = postCollection.GetValues(postDataKey);
  165. bool changed = false;
  166. if (postedValueColl != null){
  167. if (!Multiple){
  168. //single selection
  169. //int postedValue = Items.FindIndexByValue(postedValueColl[0]);
  170. int postedValue = Items.IndexOf(Items.FindByValue(postedValueColl[0]));
  171. if (postedValue != SelectedIndex){
  172. //set the SelectedIndex
  173. SelectedIndex = postedValue;
  174. changed = true;
  175. }
  176. }
  177. else{
  178. //multiple selection
  179. int postedValueCount = postedValueColl.Length;
  180. int[] arr= new int[postedValueCount];
  181. //fill an array with the posted Values
  182. for (int i = 0; i < postedValueCount; i++)
  183. arr[i] = Items.IndexOf(Items.FindByValue(postedValueColl[i]));
  184. //test if everything went fine
  185. if( postedValueCount == SelectedIndices.Length){
  186. for (int i = 0; i < postedValueCount; i++)
  187. if(arr[i] != SelectedIndices[i])
  188. changed = true;
  189. }
  190. else
  191. changed = true;
  192. //commit the posted Values
  193. if(changed)
  194. Select(arr);
  195. }
  196. }
  197. else if (SelectedIndex != -1){
  198. SelectedIndex = -1;
  199. changed = true;
  200. }
  201. return changed;
  202. }
  203. void IPostBackDataHandler.RaisePostDataChangedEvent ()
  204. {
  205. OnServerChange (EventArgs.Empty);
  206. }
  207. //starts tracking changes to the viewstate
  208. protected override void TrackViewState(){
  209. base.TrackViewState();
  210. Items.TrackViewState();
  211. }
  212. [WebCategory("Action")]
  213. [WebSysDescription("Fires when the selection changes.")]
  214. public event EventHandler ServerChange{
  215. add{
  216. Events.AddHandler(EventServerChange, value);
  217. }
  218. remove{
  219. Events.RemoveHandler(EventServerChange, value);
  220. }
  221. }
  222. [DefaultValue("")]
  223. [WebCategory("Data")]
  224. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  225. [WebSysDescription("The data member of the select.")]
  226. public virtual string DataMember{
  227. get{
  228. object viewStateDataMember = ViewState["DataMember"];
  229. if ( viewStateDataMember != null) return (String) viewStateDataMember;
  230. return String.Empty;
  231. }
  232. set{
  233. Attributes["DataMember"] = HtmlControl.AttributeToString(value);
  234. }
  235. }
  236. [DefaultValue(null)]
  237. [WebCategory("Data")]
  238. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  239. [WebSysDescription("The data source used to populate the list with data.")]
  240. public virtual object DataSource{
  241. get{
  242. return _dataSource;
  243. }
  244. set{
  245. if (value != null && !(value is IListSource)) {
  246. if (!(value is IEnumerable))
  247. throw new ArgumentException ("Invalid dataSource type");
  248. }
  249. _dataSource = value;
  250. }
  251. }
  252. [DefaultValue("")]
  253. [WebCategory("Data")]
  254. [WebSysDescription("The field in the data source that provides the item value.")]
  255. public virtual string DataTextField{
  256. get{
  257. string attr = Attributes["DataTextField"];
  258. if (attr != null){
  259. return attr;
  260. }
  261. return String.Empty;
  262. }
  263. set{
  264. Attributes["DataTextField"] = AttributeToString(value);
  265. }
  266. }
  267. [DefaultValue("")]
  268. [WebCategory("Data")]
  269. [WebSysDescription("The field in the data source that provides the item value.")]
  270. public virtual string DataValueField{
  271. get{
  272. string attr = Attributes["DataValueField"];
  273. if (attr != null)return attr;
  274. return String.Empty;
  275. }
  276. set{
  277. Attributes["DataValueField"] = AttributeToString(value);
  278. }
  279. }
  280. public override string InnerHtml{
  281. get{
  282. throw new NotSupportedException("InnerHtml is not supported by " + this.GetType().Name);
  283. }
  284. set{
  285. throw new NotSupportedException("InnerHtml is not supported by " + this.GetType().Name);
  286. }
  287. }
  288. public override string InnerText{
  289. get{
  290. throw new NotSupportedException("InnerText is not supported by " + this.GetType().Name);
  291. }
  292. set{
  293. throw new NotSupportedException("InnerText is not supported by " + this.GetType().Name);
  294. }
  295. }
  296. [Browsable(false)]
  297. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  298. public ListItemCollection Items{
  299. get{
  300. if (_items == null){
  301. _items = new ListItemCollection();
  302. if (IsTrackingViewState) _items.TrackViewState();
  303. }
  304. return _items;
  305. }
  306. }
  307. [DefaultValue("")]
  308. [WebCategory("Behavior")]
  309. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  310. public bool Multiple{
  311. get{
  312. string attr = Attributes["multiple"];
  313. if (attr != null) return (0 == String.Compare (attr, "true", true));
  314. return false;
  315. }
  316. set{
  317. Attributes["multiple"] = value.ToString ();
  318. }
  319. }
  320. [DefaultValue("")]
  321. [WebCategory("Behavior")]
  322. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  323. public string Name{
  324. get{
  325. return UniqueID;
  326. }
  327. set{
  328. //LAMESPEC
  329. return;
  330. }
  331. }
  332. [HtmlControlPersistable (false)]
  333. [Browsable(false)]
  334. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  335. public virtual int SelectedIndex {
  336. get{
  337. for (int i=0; i<Items.Count; i++){
  338. if (Items[i].Selected == true) return i;
  339. }
  340. if (Size<=1 && !Multiple){
  341. if(Items.Count > 0) Items[0].Selected = true;
  342. return 0;
  343. }
  344. return -1;
  345. }
  346. set{
  347. if(Items.Count == 0){
  348. _cachedSelectedIndex = value;
  349. return;
  350. }
  351. if (value < -1 || value >= Items.Count)
  352. throw new ArgumentOutOfRangeException();
  353. ClearSelection();
  354. if (value >= 0)
  355. Items[value].Selected = true;
  356. }
  357. }
  358. protected virtual int[] SelectedIndices {
  359. get{
  360. int[] indices = new int[3];
  361. int indicesCount = 0;
  362. for(int i=0; i < Items.Count; i++){
  363. if (Items[i].Selected){
  364. if( indicesCount == (int) indices.Length){
  365. int[] temp = new int[indicesCount + indicesCount];
  366. indices.CopyTo(temp,0);
  367. indices = temp;
  368. }
  369. indices[indicesCount] = i;
  370. indicesCount++;
  371. }
  372. }
  373. int[] arr = new int[indicesCount];
  374. System.Array.Copy(indices,0,arr,0,indicesCount);
  375. return arr;
  376. }
  377. }
  378. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  379. public int Size{
  380. get{
  381. string attr = Attributes["size"];
  382. if (attr != null){
  383. return Int32.Parse(attr, CultureInfo.InvariantCulture);;
  384. }
  385. return -1;
  386. }
  387. set{
  388. Attributes["size"] = AttributeToString(value);
  389. }
  390. }
  391. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  392. public string Value {
  393. get{
  394. int selectedIndex = SelectedIndex;
  395. if (selectedIndex >=0 && selectedIndex < Items.Count){
  396. return Items[selectedIndex].Value;
  397. }
  398. return String.Empty;
  399. }
  400. set{
  401. int findValue = Items.IndexOf(Items.FindByValue(value));
  402. if (findValue >= 0) SelectedIndex = findValue;
  403. }
  404. }
  405. } // class HtmlSelect
  406. } // namespace System.Web.UI.HtmlControls