HtmlSelect.cs 11 KB

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