HtmlSelect.cs 13 KB

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