HtmlSelect.cs 12 KB

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