HtmlSelect.cs 13 KB

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