HtmlSelect.cs 11 KB

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