HtmlSelect.cs 13 KB

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