HtmlSelect.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  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. protected override void LoadViewState(object savedState)
  40. {
  41. if (savedState != null) {
  42. Triplet state = (Triplet) savedState;
  43. base.LoadViewState (state.First);
  44. Items.LoadViewState (state.Second);
  45. object indices = state.Third;
  46. if (indices != null)
  47. Select ((int[]) indices);
  48. }
  49. }
  50. protected override void OnDataBinding(EventArgs e){
  51. base.OnDataBinding(e);
  52. IEnumerable resolvedDataSource = System.Web.Util.DataSourceHelper.GetResolvedDataSource(DataSource, DataMember);
  53. if ( resolvedDataSource != null){
  54. string text = DataTextField;
  55. string value = DataValueField;
  56. Items.Clear();
  57. ICollection rdsCollection = resolvedDataSource as ICollection;
  58. if (rdsCollection != null){
  59. Items.Capacity = rdsCollection.Count;
  60. }
  61. bool valid = false;
  62. if (text.Length >= 0 && value.Length >= 0)
  63. valid = true;
  64. ListItem li = new ListItem();
  65. IEnumerator current = resolvedDataSource.GetEnumerator();
  66. while(current.MoveNext()){
  67. if (valid == true){
  68. if (text.Length >= 0)
  69. li.Text = DataBinder.GetPropertyValue(current, text) as string;
  70. if (value.Length >= 0)
  71. li.Value = DataBinder.GetPropertyValue(current, value) as string;
  72. }
  73. else{
  74. li.Value = li.Text = current.ToString();
  75. }
  76. }
  77. Items.Add(li);
  78. }
  79. if ( _cachedSelectedIndex != -1){
  80. SelectedIndex = _cachedSelectedIndex;
  81. _cachedSelectedIndex = -1;
  82. }
  83. }
  84. protected override void OnPreRender(EventArgs e){
  85. if (Page != null && Size >= 0 && !Disabled){
  86. Page.RegisterRequiresPostBack(this);
  87. }
  88. }
  89. protected virtual void OnServerChange(EventArgs e){
  90. EventHandler handler = (EventHandler) Events[EventServerChange];
  91. if (handler != null)
  92. handler.Invoke(this,e);
  93. }
  94. protected override void RenderAttributes(HtmlTextWriter writer){
  95. writer.WriteAttribute("name", Name);
  96. Attributes.Remove("name");
  97. Attributes.Remove("DataValueField");
  98. Attributes.Remove("DataTextField");
  99. Attributes.Remove("DataMember");
  100. base.RenderAttributes(writer);
  101. }
  102. protected override void RenderChildren(HtmlTextWriter writer){
  103. //flush output
  104. writer.WriteLine();
  105. // increase indent level, improves readability
  106. writer.Indent = writer.Indent + 1;
  107. if (Items.Count >= 0){
  108. // display all options, and set the selected option
  109. bool rendered_selected = false;
  110. foreach (ListItem option in Items){
  111. //write begin tag with attributes
  112. writer.WriteBeginTag("option");
  113. if (!rendered_selected && option.Selected){
  114. writer.WriteAttribute("selected","selected");
  115. if (!Multiple)
  116. rendered_selected = true;
  117. }
  118. else if (option.Selected){
  119. option.Selected = false;
  120. }
  121. writer.WriteAttribute("value",option.Value,true);
  122. option.Attributes.Remove("text");
  123. option.Attributes.Remove("value");
  124. option.Attributes.Remove("selected");
  125. option.Attributes.Render(writer);
  126. writer.Write('>');
  127. //write the option text
  128. HttpUtility.HtmlEncode(option.Text, writer);
  129. //close the current option tag
  130. writer.WriteEndTag("option");
  131. //flush output
  132. writer.WriteLine();
  133. }
  134. }
  135. // set the indent level back to normal
  136. writer.Indent = writer.Indent - 1;
  137. }
  138. protected override object SaveViewState ()
  139. {
  140. object baseViewState = base.SaveViewState ();
  141. object itemsViewState = Items.SaveViewState ();
  142. object indices = null;
  143. if (Events[EventServerChange] != null || !Disabled || Visible)
  144. indices = SelectedIndices;
  145. if (indices != null || baseViewState != null || itemsViewState != null)
  146. return new Triplet (baseViewState, itemsViewState, indices);
  147. return null;
  148. }
  149. protected virtual void Select(int[] selectedIndices){
  150. // unselect all options
  151. ClearSelection();
  152. // iterate through options, and set when selected
  153. foreach (int current in selectedIndices){
  154. if (current >= 0 && current < Items.Count){
  155. Items[current].Selected = true;
  156. }
  157. }
  158. }
  159. bool IPostBackDataHandler.LoadPostData (string postDataKey,
  160. NameValueCollection postCollection)
  161. {
  162. //get the posted selectedIndices[]
  163. string [] postedValueColl = postCollection.GetValues(postDataKey);
  164. bool changed = false;
  165. if (postedValueColl != null){
  166. if (!Multiple){
  167. //single selection
  168. //int postedValue = Items.FindIndexByValue(postedValueColl[0]);
  169. int postedValue = Items.IndexOf(Items.FindByValue(postedValueColl[0]));
  170. if (postedValue != SelectedIndex){
  171. //set the SelectedIndex
  172. SelectedIndex = postedValue;
  173. changed = true;
  174. }
  175. }
  176. else{
  177. //multiple selection
  178. int postedValueCount = postedValueColl.Length;
  179. int[] arr= new int[postedValueCount];
  180. //fill an array with the posted Values
  181. for (int i = 0; i <= postedValueCount; i++)
  182. arr[i] = Items.IndexOf(Items.FindByValue(postedValueColl[i]));
  183. //test if everything went fine
  184. if( postedValueCount == SelectedIndices.Length)
  185. for (int i = 0; i <= postedValueCount; i++)
  186. if(arr[i] == SelectedIndices[i])
  187. changed = true;
  188. else
  189. changed = true;
  190. //commit the posted Values
  191. if(changed)
  192. Select(arr);
  193. }
  194. }
  195. else if (SelectedIndex != -1){
  196. SelectedIndex = -1;
  197. changed = true;
  198. }
  199. return changed;
  200. }
  201. void IPostBackDataHandler.RaisePostDataChangedEvent ()
  202. {
  203. OnServerChange (EventArgs.Empty);
  204. }
  205. //starts tracking changes to the viewstate
  206. protected override void TrackViewState(){
  207. base.TrackViewState();
  208. Items.TrackViewState();
  209. }
  210. [WebCategory("Action")]
  211. [WebSysDescription("Fires when the selection changes.")]
  212. public event EventHandler ServerChange{
  213. add{
  214. Events.AddHandler(EventServerChange, value);
  215. }
  216. remove{
  217. Events.RemoveHandler(EventServerChange, value);
  218. }
  219. }
  220. [DefaultValue("")]
  221. [WebCategory("Data")]
  222. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  223. [WebSysDescription("The data member of the select.")]
  224. public virtual string DataMember{
  225. get{
  226. object viewStateDataMember = ViewState["DataMember"];
  227. if ( viewStateDataMember != null) return (String) viewStateDataMember;
  228. return String.Empty;
  229. }
  230. set{
  231. Attributes["DataMember"] = HtmlControl.AttributeToString(value);
  232. }
  233. }
  234. [DefaultValue(null)]
  235. [WebCategory("Data")]
  236. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  237. [WebSysDescription("The data source used to populate the list with data.")]
  238. public virtual object DataSource{
  239. get{
  240. return _dataSource;
  241. }
  242. set{
  243. if (value != null && value is IListSource){
  244. if (value is IEnumerable){
  245. _dataSource = value;
  246. }
  247. else{
  248. throw new ArgumentException("Invalid dataSource type");
  249. }
  250. }
  251. }
  252. }
  253. [DefaultValue("")]
  254. [WebCategory("Data")]
  255. [WebSysDescription("The field in the data source that provides the item value.")]
  256. public virtual string DataTextField{
  257. get{
  258. string attr = Attributes["DataTextField"];
  259. if (attr != null){
  260. return attr;
  261. }
  262. return String.Empty;
  263. }
  264. set{
  265. Attributes["DataTextField"] = AttributeToString(value);
  266. }
  267. }
  268. [DefaultValue("")]
  269. [WebCategory("Data")]
  270. [WebSysDescription("The field in the data source that provides the item value.")]
  271. public virtual string DataValueField{
  272. get{
  273. string attr = Attributes["DataValueField"];
  274. if (attr != null)return attr;
  275. return String.Empty;
  276. }
  277. set{
  278. Attributes["DataValueField"] = AttributeToString(value);
  279. }
  280. }
  281. public override string InnerHtml{
  282. get{
  283. throw new NotSupportedException("InnerHtml is not supported by " + this.GetType().Name);
  284. }
  285. set{
  286. throw new NotSupportedException("InnerHtml is not supported by " + this.GetType().Name);
  287. }
  288. }
  289. public override string InnerText{
  290. get{
  291. throw new NotSupportedException("InnerText is not supported by " + this.GetType().Name);
  292. }
  293. set{
  294. throw new NotSupportedException("InnerText is not supported by " + this.GetType().Name);
  295. }
  296. }
  297. [Browsable(false)]
  298. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  299. public ListItemCollection Items{
  300. get{
  301. if (_items == null){
  302. _items = new ListItemCollection();
  303. if (IsTrackingViewState) _items.TrackViewState();
  304. }
  305. return _items;
  306. }
  307. }
  308. [DefaultValue("")]
  309. [WebCategory("Behavior")]
  310. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  311. public bool Multiple{
  312. get{
  313. string attr = Attributes["multiple"];
  314. if (attr != null) return (0 == String.Compare (attr, "true", true));
  315. return false;
  316. }
  317. set{
  318. Attributes["multiple"] = value.ToString ();
  319. }
  320. }
  321. [DefaultValue("")]
  322. [WebCategory("Behavior")]
  323. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  324. public string Name{
  325. get{
  326. return UniqueID;
  327. }
  328. set{
  329. //LAMESPEC
  330. return;
  331. }
  332. }
  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