2 // System.Web.UI.Control.cs
5 // Bob Smith <bob@thestuff.net>
6 // Gonzalo Paniagua Javier (gonzalo@ximian.com
7 // Andreas Nahr (ClassDevelopment@A-SoftTech.com)
10 // (c) 2002,2003 Ximian, Inc. (http://www.ximian.com)
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 using System.Collections;
36 using System.ComponentModel;
37 using System.ComponentModel.Design;
38 using System.ComponentModel.Design.Serialization;
40 using System.Web.Util;
42 namespace System.Web.UI
44 [DefaultProperty ("ID"), DesignerCategory ("Code"), ToolboxItemFilter ("System.Web.UI", ToolboxItemFilterType.Require)]
45 [ToolboxItem ("System.Web.UI.Design.WebControlToolboxItem, " + Consts.AssemblySystem_Design)]
46 [Designer ("System.Web.UI.Design.ControlDesigner, " + Consts.AssemblySystem_Design, typeof (IDesigner))]
47 [DesignerSerializer ("Microsoft.VSDesigner.WebForms.ControlCodeDomSerializer, " + Consts.AssemblyMicrosoft_VSDesigner, "System.ComponentModel.Design.Serialization.CodeDomSerializer, " + Consts.AssemblySystem_Design)]
48 public class Control : IComponent, IDisposable, IParserAccessor, IDataBindingsAccessor
50 private static readonly object DataBindingEvent = new object();
51 private static readonly object DisposedEvent = new object();
52 private static readonly object InitEvent = new object();
53 private static readonly object LoadEvent = new object();
54 private static readonly object PreRenderEvent = new object();
55 private static readonly object UnloadEvent = new object();
56 private string uniqueID;
57 private string _userId;
59 private ControlCollection _controls;
60 private bool _enableViewState = true;
61 private IDictionary _childViewStates;
62 private bool _isNamingContainer;
63 private Control _namingContainer;
65 private Control _parent;
67 private bool _visible = true;
68 private bool visibleChanged;
69 private HttpContext _context;
70 private bool _childControlsCreated;
71 private StateBag _viewState;
72 private bool _trackViewState;
73 private EventHandlerList _events;
74 private RenderMethod _renderMethodDelegate;
75 private bool autoID = true;
76 private bool creatingControls;
77 private bool bindingContainer = true;
78 private bool autoEventWireup = true;
86 DataBindingCollection dataBindings;
87 Hashtable pendingVS; // may hold unused viewstate data from child controls
91 if (this is INamingContainer) _isNamingContainer = true;
\r
94 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
95 [EditorBrowsable (EditorBrowsableState.Never), Browsable (false)]
\r
96 public Control BindingContainer
\r
99 Control container = NamingContainer;
\r
100 if (!container.bindingContainer)
\r
101 container = container.BindingContainer;
\r
106 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
108 [WebSysDescription ("An Identification of the control that is rendered.")]
\r
109 public virtual string ClientID {
\r
111 string client = UniqueID;
\r
113 if (client != null)
\r
114 client = client.Replace (':', '_');
\r
120 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
122 [WebSysDescription ("The child controls of this control.")]
\r
123 public virtual ControlCollection Controls //DIT
\r
127 if (_controls == null) _controls = CreateControlCollection();
\r
132 [DefaultValue (true), WebCategory ("FIXME")]
133 [WebSysDescription ("An Identification of the control that is rendered.")]
\r
134 public virtual bool EnableViewState //DIT
\r
138 return _enableViewState;
\r
142 _enableViewState = value;
\r
146 [MergableProperty (false), ParenthesizePropertyName (true)]
147 [WebSysDescription ("The name of the control that is rendered.")]
\r
148 public virtual string ID {
\r
150 return (id_set ? _userId : null);
159 NullifyUniqueID ();
\r
163 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
165 [WebSysDescription ("The container that this control is part of. The control's name has to be unique within the container.")]
\r
166 public virtual Control NamingContainer //DIT
\r
170 if (_namingContainer == null && _parent != null)
\r
172 if (_parent._isNamingContainer == false)
\r
173 _namingContainer = _parent.NamingContainer;
\r
175 _namingContainer = _parent;
\r
177 return _namingContainer;
\r
181 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
183 [WebSysDescription ("The webpage that this control resides on.")]
\r
184 public virtual Page Page //DIT
\r
188 if (_page == null && _parent != null) _page = _parent.Page;
\r
197 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
199 [WebSysDescription ("The parent control of this control.")]
\r
200 public virtual Control Parent //DIT
\r
208 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
209 [EditorBrowsable (EditorBrowsableState.Advanced), Browsable (false)]
210 [WebSysDescription ("The site this control is part of.")]
\r
211 public ISite Site //DIT
\r
223 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
225 [WebSysDescription ("A virtual directory containing the parent of the control.")]
\r
226 public virtual string TemplateSourceDirectory {
\r
227 get { return (_parent == null) ? String.Empty : _parent.TemplateSourceDirectory; }
\r
230 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
232 [WebSysDescription ("The unique ID of the control.")]
\r
233 public virtual string UniqueID {
\r
235 if (uniqueID != null)
\r
238 if (_namingContainer == null) {
\r
242 if (_userId == null)
\r
243 _userId = _namingContainer.GetDefaultName ();
\r
245 string prefix = _namingContainer.UniqueID;
\r
246 if (_namingContainer == _page || prefix == null) {
\r
247 uniqueID = _userId;
\r
251 uniqueID = prefix + ":" + _userId;
\r
256 [DefaultValue (true), Bindable (true), WebCategory ("FIXME")]
257 [WebSysDescription ("Visiblity state of the control.")]
258 public virtual bool Visible {
260 if (_visible == false)
264 return _parent.Visible;
270 if (value != _visible) {
271 if (IsTrackingViewState)
272 visibleChanged = true;
279 protected bool ChildControlsCreated //DIT
\r
283 return _childControlsCreated;
\r
287 if (value == false && _childControlsCreated == true)
\r
289 _childControlsCreated = value;
\r
294 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
295 protected virtual HttpContext Context //DIT
\r
299 HttpContext context;
\r
300 if (_context != null)
\r
302 if (_parent == null)
\r
303 return HttpContext.Current;
\r
304 context = _parent.Context;
\r
305 if (context != null)
\r
307 return HttpContext.Current;
\r
310 protected EventHandlerList Events //DIT
\r
314 if (_events == null)
\r
316 _events = new EventHandlerList();
\r
321 protected bool HasChildViewState //DIT
\r
325 if (_childViewStates == null) return false;
\r
329 protected bool IsTrackingViewState //DIT
\r
333 return _trackViewState;
\r
338 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
339 [WebSysDescription ("ViewState")]
340 protected virtual StateBag ViewState
\r
344 if(_viewState == null)
\r
345 _viewState = new StateBag (ViewStateIgnoresCase);
\r
347 if (IsTrackingViewState)
\r
348 _viewState.TrackViewState ();
\r
355 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
356 protected virtual bool ViewStateIgnoresCase
\r
363 internal bool AutoEventWireup {
\r
364 get { return autoEventWireup; }
\r
365 set { autoEventWireup = value; }
\r
368 internal void SetBindingContainer (bool isBC)
\r
370 bindingContainer = isBC;
\r
373 internal void ResetChildNames ()
\r
375 defaultNumberID = 0;
\r
378 string GetDefaultName ()
\r
380 return "_ctrl" + defaultNumberID++;
\r
383 void NullifyUniqueID ()
\r
386 if (_controls == null)
\r
389 foreach (Control c in _controls)
\r
390 c.NullifyUniqueID ();
\r
393 protected internal virtual void AddedControl (Control control, int index)
\r
395 /* Ensure the control don't have more than 1 parent */
396 if (control._parent != null)
397 control._parent.Controls.Remove (control);
399 control._parent = this;
400 control._page = _page;
401 Control nc = _isNamingContainer ? this : NamingContainer;
404 control._namingContainer = nc;
405 if (control.AutoID == true && control._userId == null)
406 control._userId = nc.GetDefaultName () + "a";
409 if (initing || inited)
410 control.InitRecursive (nc);
412 if (viewStateLoaded || loaded) {
413 if (pendingVS != null) {
414 object vs = pendingVS [index];
416 pendingVS.Remove (index);
417 if (pendingVS.Count == 0)
420 control.LoadViewStateRecursive (vs);
426 control.LoadRecursive ();
429 control.PreRenderRecursiveInternal ();
432 protected virtual void AddParsedSubObject(object obj) //DIT
\r
434 WebTrace.PushContext ("Control.AddParsedSubobject ()");
\r
435 Control c = obj as Control;
\r
436 WebTrace.WriteLine ("Start: {0} -> {1}", obj, (c != null) ? c.ID : String.Empty);
\r
437 if (c != null) Controls.Add(c);
\r
438 WebTrace.WriteLine ("End");
\r
439 WebTrace.PopContext ();
\r
442 protected void BuildProfileTree(string parentId, bool calcViewState)
\r
447 protected void ClearChildViewState ()
452 protected virtual void CreateChildControls() {} //DIT
\r
453 protected virtual ControlCollection CreateControlCollection() //DIT
\r
455 return new ControlCollection(this);
\r
458 protected virtual void EnsureChildControls () //DIT
\r
460 if (ChildControlsCreated == false && !creatingControls) {
\r
461 creatingControls = true;
\r
462 CreateChildControls();
\r
463 ChildControlsCreated = true;
\r
464 creatingControls = false;
\r
468 protected bool IsLiteralContent()
470 if (_controls != null)
471 if (_controls.Count == 1)
472 if (_controls[0] is LiteralControl)
477 public virtual Control FindControl (string id)
\r
479 return FindControl (id, 0);
\r
482 Control LookForControlByName (string id)
\r
487 foreach (Control c in _controls) {
\r
488 if (String.Compare (id, c._userId, true) == 0)
\r
491 if (!c._isNamingContainer && c.HasChildren) {
\r
492 Control child = c.LookForControlByName (id);
\r
501 protected virtual Control FindControl (string id, int pathOffset)
\r
503 EnsureChildControls ();
\r
504 if (_controls == null)
\r
507 Control namingContainer = null;
\r
508 if (!_isNamingContainer) {
\r
509 namingContainer = NamingContainer;
\r
510 if (namingContainer == null)
\r
513 return namingContainer.FindControl (id, pathOffset);
\r
516 int colon = id.IndexOf (':', pathOffset);
\r
518 return LookForControlByName (id.Substring (pathOffset));
\r
520 string idfound = id.Substring (pathOffset, colon - pathOffset);
\r
521 namingContainer = LookForControlByName (idfound);
\r
522 if (namingContainer == null)
\r
525 return namingContainer.FindControl (id, colon + 1);
\r
528 protected virtual void LoadViewState(object savedState)
530 if (savedState != null) {
531 ViewState.LoadViewState (savedState);
532 object o = ViewState ["Visible"];
535 visibleChanged = true;
540 [MonoTODO("Secure?")]
\r
541 protected string MapPathSecure(string virtualPath)
\r
543 string combined = UrlUtils.Combine (TemplateSourceDirectory, virtualPath);
\r
544 return Context.Request.MapPath (combined);
\r
547 protected virtual bool OnBubbleEvent(object source, EventArgs args) //DIT
\r
551 protected virtual void OnDataBinding(EventArgs e) //DIT
\r
553 if (_events != null)
\r
555 EventHandler eh = (EventHandler)(_events[DataBindingEvent]);
\r
556 if (eh != null) eh(this, e);
\r
559 protected virtual void OnInit(EventArgs e) //DIT
\r
561 if (_events != null)
\r
563 EventHandler eh = (EventHandler)(_events[InitEvent]);
\r
564 if (eh != null) eh(this, e);
\r
567 protected virtual void OnLoad(EventArgs e) //DIT
\r
569 if (_events != null)
\r
571 EventHandler eh = (EventHandler)(_events[LoadEvent]);
\r
572 if (eh != null) eh(this, e);
\r
575 protected virtual void OnPreRender(EventArgs e) //DIT
\r
577 if (_events != null)
\r
579 EventHandler eh = (EventHandler)(_events[PreRenderEvent]);
\r
580 if (eh != null) eh(this, e);
\r
583 protected virtual void OnUnload(EventArgs e) //DIT
\r
585 if (_events != null)
\r
587 EventHandler eh = (EventHandler)(_events[UnloadEvent]);
\r
588 if (eh != null) eh(this, e);
\r
592 protected void RaiseBubbleEvent(object source, EventArgs args)
\r
594 Control c = Parent;
\r
595 while (c != null) {
\r
596 if (c.OnBubbleEvent (source, args))
\r
602 protected virtual void Render(HtmlTextWriter writer) //DIT
\r
604 RenderChildren(writer);
\r
607 protected virtual void RenderChildren(HtmlTextWriter writer) //DIT
\r
609 if (_renderMethodDelegate != null)
\r
610 _renderMethodDelegate(writer, this);
\r
611 else if (_controls != null)
\r
612 foreach (Control c in _controls)
\r
613 c.RenderControl(writer);
\r
616 protected virtual object SaveViewState ()
618 if (visibleChanged) {
619 ViewState ["Visible"] = Visible;
620 } else if (_viewState == null) {
624 return _viewState.SaveViewState ();
627 protected virtual void TrackViewState()
\r
629 if (_viewState != null)
\r
630 _viewState.TrackViewState ();
\r
631 _trackViewState = true;
\r
634 public virtual void Dispose()
\r
636 if (_events != null)
\r
638 EventHandler eh = (EventHandler) _events [DisposedEvent];
\r
640 eh(this, EventArgs.Empty);
\r
644 internal bool HasChildren
\r
646 get { return (_controls != null && _controls.Count > 0); }
\r
649 [WebCategory ("FIXME")]
650 [WebSysDescription ("Raised when the contols databound properties are evaluated.")]
\r
651 public event EventHandler DataBinding //DIT
\r
655 Events.AddHandler(DataBindingEvent, value);
\r
659 Events.RemoveHandler(DataBindingEvent, value);
\r
663 [WebSysDescription ("Raised when the contol is disposed.")]
\r
664 public event EventHandler Disposed //DIT
\r
668 Events.AddHandler(DisposedEvent, value);
\r
672 Events.RemoveHandler(DisposedEvent, value);
\r
676 [WebSysDescription ("Raised when the page containing the control is initialized.")]
\r
677 public event EventHandler Init //DIT
\r
681 Events.AddHandler(InitEvent, value);
\r
685 Events.RemoveHandler(InitEvent, value);
\r
689 [WebSysDescription ("Raised after the page containing the control has been loaded.")]
\r
690 public event EventHandler Load //DIT
\r
694 Events.AddHandler(LoadEvent, value);
\r
698 Events.RemoveHandler(LoadEvent, value);
\r
702 [WebSysDescription ("Raised before the page containing the control is rendered.")]
\r
703 public event EventHandler PreRender //DIT
\r
707 Events.AddHandler(PreRenderEvent, value);
\r
711 Events.RemoveHandler(PreRenderEvent, value);
\r
715 [WebSysDescription ("Raised when the page containing the control is unloaded.")]
\r
716 public event EventHandler Unload //DIT
\r
720 Events.AddHandler(UnloadEvent, value);
\r
724 Events.RemoveHandler(UnloadEvent, value);
\r
728 public virtual void DataBind() //DIT
\r
731 bool foundDataItem = false;
733 if (_isNamingContainer && Page != null) {
734 object o = DataBinder.GetDataItem (this, out foundDataItem);
736 Page.PushDataItemContext (o);
742 OnDataBinding (EventArgs.Empty);
748 Page.PopDataItemContext ();
757 void DataBindChildren ()
759 if (_controls == null)
762 foreach (Control c in _controls)
767 public virtual bool HasControls ()
769 return (_controls != null && _controls.Count > 0);
772 public void RenderControl(HtmlTextWriter writer)
778 public string ResolveUrl(string relativeUrl)
780 if (relativeUrl == null)
781 throw new ArgumentNullException ("relativeUrl");
783 if (relativeUrl == "")
786 if (relativeUrl [0] == '#')
789 string ts = TemplateSourceDirectory;
790 if (ts == "" || !UrlUtils.IsRelativeUrl (relativeUrl))
793 if (relativeUrl.IndexOf ('/') == -1 && relativeUrl [0] != '.' && relativeUrl != "..")
796 HttpResponse resp = Context.Response;
797 return resp.ApplyAppPathModifier (UrlUtils.Combine (ts, relativeUrl));
800 [EditorBrowsable (EditorBrowsableState.Advanced)]
\r
801 public void SetRenderMethodDelegate(RenderMethod renderMethod) //DIT
\r
803 _renderMethodDelegate = renderMethod;
\r
806 internal void LoadRecursive()
\r
808 OnLoad (EventArgs.Empty);
\r
809 if (_controls != null) {
\r
810 foreach (Control c in _controls)
\r
811 c.LoadRecursive ();
\r
816 internal void UnloadRecursive(Boolean dispose)
\r
818 if (_controls != null) {
\r
819 foreach (Control c in _controls)
\r
820 c.UnloadRecursive (dispose);
\r
823 OnUnload (EventArgs.Empty);
\r
828 internal void PreRenderRecursiveInternal()
831 EnsureChildControls ();
832 OnPreRender (EventArgs.Empty);
833 if (_controls == null)
836 foreach (Control c in _controls)
837 c.PreRenderRecursiveInternal ();
842 internal void InitRecursive(Control namingContainer)
\r
844 if (_controls != null) {
\r
845 if (_isNamingContainer)
\r
846 namingContainer = this;
\r
848 if (namingContainer != null &&
\r
849 namingContainer._userId == null &&
\r
850 namingContainer.autoID)
\r
851 namingContainer._userId = namingContainer.GetDefaultName () + "b";
\r
853 foreach (Control c in _controls) {
\r
855 c._namingContainer = namingContainer;
\r
856 if (namingContainer != null && c._userId == null && c.autoID)
\r
857 c._userId = namingContainer.GetDefaultName () + "c";
\r
859 c.InitRecursive (namingContainer);
\r
864 OnInit (EventArgs.Empty);
\r
870 internal object SaveViewStateRecursive ()
872 if (!EnableViewState)
875 ArrayList controlList = null;
876 ArrayList controlStates = null;
879 foreach (Control ctrl in Controls) {
880 object ctrlState = ctrl.SaveViewStateRecursive ();
882 if (ctrlState == null)
885 if (controlList == null) {
886 controlList = new ArrayList ();
887 controlStates = new ArrayList ();
890 controlList.Add (idx);
891 controlStates.Add (ctrlState);
894 object thisState = SaveViewState ();
895 if (thisState == null && controlList == null && controlStates == null)
898 return new Triplet (thisState, controlList, controlStates);
901 internal void LoadViewStateRecursive (object savedState)
903 if (!EnableViewState || savedState == null)
906 Triplet savedInfo = (Triplet) savedState;
907 LoadViewState (savedInfo.First);
909 ArrayList controlList = savedInfo.Second as ArrayList;
910 if (controlList == null)
912 ArrayList controlStates = savedInfo.Third as ArrayList;
913 int nControls = controlList.Count;
914 for (int i = 0; i < nControls; i++) {
915 int k = (int) controlList [i];
916 if (k < Controls.Count && controlStates != null) {
917 Control c = Controls [k];
918 c.LoadViewStateRecursive (controlStates [i]);
920 if (pendingVS == null)
921 pendingVS = new Hashtable ();
923 pendingVS [k] = controlStates [i];
927 viewStateLoaded = true;
930 void IParserAccessor.AddParsedSubObject(object obj)
\r
932 AddParsedSubObject(obj);
\r
935 DataBindingCollection IDataBindingsAccessor.DataBindings
\r
939 if(dataBindings == null)
\r
940 dataBindings = new DataBindingCollection();
\r
941 return dataBindings;
\r
945 bool IDataBindingsAccessor.HasDataBindings
\r
949 return (dataBindings!=null && dataBindings.Count>0);
\r
953 internal bool AutoID
\r
955 get { return autoID; }
\r
957 if (value == false && _isNamingContainer)
\r
964 internal void PreventAutoID()
\r
969 protected internal virtual void RemovedControl (Control control)
\r
971 control.UnloadRecursive (false);
\r
972 control._parent = null;
\r
973 control._page = null;
\r
974 control._namingContainer = null;
\r
978 protected string GetWebResourceUrl (string resourceName)
980 return Page.GetWebResourceUrl (GetType(), resourceName);