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 using System.Collections;
15 using System.ComponentModel;
16 using System.ComponentModel.Design;
17 using System.ComponentModel.Design.Serialization;
19 using System.Web.Util;
21 namespace System.Web.UI
23 [DefaultProperty ("ID"), DesignerCategory ("Code"), ToolboxItemFilter ("System.Web.UI", ToolboxItemFilterType.Require)]
24 [ToolboxItem ("System.Web.UI.Design.WebControlToolboxItem, " + Consts.AssemblySystem_Design)]
25 [Designer ("System.Web.UI.Design.ControlDesigner, " + Consts.AssemblySystem_Design, typeof (IDesigner))]
26 [DesignerSerializer ("Microsoft.VSDesigner.WebForms.ControlCodeDomSerializer, " + Consts.AssemblyMicrosoft_VSDesigner, "System.ComponentModel.Design.Serialization.CodeDomSerializer, " + Consts.AssemblySystem_Design)]
27 public class Control : IComponent, IDisposable, IParserAccessor, IDataBindingsAccessor
29 private static readonly object DataBindingEvent = new object();
30 private static readonly object DisposedEvent = new object();
31 private static readonly object InitEvent = new object();
32 private static readonly object LoadEvent = new object();
33 private static readonly object PreRenderEvent = new object();
34 private static readonly object UnloadEvent = new object();
35 private string uniqueID;
36 private string _userId;
38 private string _cachedClientId;
39 private ControlCollection _controls;
40 private bool _enableViewState = true;
41 private IDictionary _childViewStates; //TODO: Not sure datatype. Placeholder guess.
42 private bool _isNamingContainer;
43 private Control _namingContainer;
45 private Control _parent;
47 private bool _visible = true;
48 private bool visibleChanged;
49 private HttpContext _context;
50 private bool _childControlsCreated;
51 private StateBag _viewState;
52 private bool _trackViewState;
53 private EventHandlerList _events = new EventHandlerList();
54 private RenderMethod _renderMethodDelegate;
55 private bool autoID = true;
56 private bool creatingControls;
57 private bool bindingContainer = true;
58 private bool autoEventWireup = true;
66 DataBindingCollection dataBindings;
67 Hashtable pendingVS; // may hold unused viewstate data from child controls
71 if (this is INamingContainer) _isNamingContainer = true;
\r
74 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
75 [EditorBrowsable (EditorBrowsableState.Never), Browsable (false)]
\r
76 public Control BindingContainer
\r
79 Control container = NamingContainer;
\r
80 if (!container.bindingContainer)
\r
81 container = container.BindingContainer;
\r
86 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
88 [WebSysDescription ("An Identification of the control that is rendered.")]
\r
89 public virtual string ClientID {
\r
91 string client = UniqueID;
\r
94 client = client.Replace (':', '_');
\r
100 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
102 [WebSysDescription ("The child controls of this control.")]
\r
103 public virtual ControlCollection Controls //DIT
\r
107 if (_controls == null) _controls = CreateControlCollection();
\r
112 [DefaultValue (true), WebCategory ("FIXME")]
113 [WebSysDescription ("An Identification of the control that is rendered.")]
\r
114 public virtual bool EnableViewState //DIT
\r
118 return _enableViewState;
\r
122 _enableViewState = value;
\r
126 [MergableProperty (false), ParenthesizePropertyName (true)]
127 [WebSysDescription ("The name of the control that is rendered.")]
\r
128 public virtual string ID {
\r
130 return (id_set ? _userId : null);
139 NullifyUniqueID ();
\r
143 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
145 [WebSysDescription ("The container that this control is part of. The control's name has to be unique within the container.")]
\r
146 public virtual Control NamingContainer //DIT
\r
150 if (_namingContainer == null && _parent != null)
\r
152 if (_parent._isNamingContainer == false)
\r
153 _namingContainer = _parent.NamingContainer;
\r
155 _namingContainer = _parent;
\r
157 return _namingContainer;
\r
161 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
163 [WebSysDescription ("The webpage that this control resides on.")]
\r
164 public virtual Page Page //DIT
\r
168 if (_page == null && _parent != null) _page = _parent.Page;
\r
177 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
179 [WebSysDescription ("The parent control of this control.")]
\r
180 public virtual Control Parent //DIT
\r
188 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
189 [EditorBrowsable (EditorBrowsableState.Advanced), Browsable (false)]
190 [WebSysDescription ("The site this control is part of.")]
\r
191 public ISite Site //DIT
\r
203 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
205 [WebSysDescription ("A virtual directory containing the parent of the control.")]
\r
206 public virtual string TemplateSourceDirectory {
\r
207 get { return (_parent == null) ? String.Empty : _parent.TemplateSourceDirectory; }
\r
210 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
212 [WebSysDescription ("The unique ID of the control.")]
\r
213 public virtual string UniqueID {
\r
215 if (uniqueID != null)
\r
218 if (_namingContainer == null) {
\r
222 if (_userId == null)
\r
223 _userId = _namingContainer.GetDefaultName ();
\r
225 string prefix = _namingContainer.UniqueID;
\r
226 if (_namingContainer == _page || prefix == null) {
\r
227 uniqueID = _userId;
\r
231 uniqueID = prefix + ":" + _userId;
\r
236 [DefaultValue (true), Bindable (true), WebCategory ("FIXME")]
237 [WebSysDescription ("Visiblity state of the control.")]
238 public virtual bool Visible {
240 if (_visible == false)
244 return _parent.Visible;
250 if (value != _visible) {
251 if (IsTrackingViewState)
252 visibleChanged = true;
259 protected bool ChildControlsCreated //DIT
\r
263 return _childControlsCreated;
\r
267 if (value == false && _childControlsCreated == true)
\r
269 _childControlsCreated = value;
\r
272 protected virtual HttpContext Context //DIT
\r
276 HttpContext context;
\r
277 if (_context != null)
\r
279 if (_parent == null)
\r
280 return HttpContext.Current;
\r
281 context = _parent.Context;
\r
282 if (context != null)
\r
284 return HttpContext.Current;
\r
287 protected EventHandlerList Events //DIT
\r
291 if (_events == null)
\r
293 _events = new EventHandlerList();
\r
298 protected bool HasChildViewState //DIT
\r
302 if (_childViewStates == null) return false;
\r
306 protected bool IsTrackingViewState //DIT
\r
310 return _trackViewState;
\r
313 protected virtual StateBag ViewState
\r
317 if(_viewState == null)
\r
318 _viewState = new StateBag (ViewStateIgnoresCase);
\r
320 if (IsTrackingViewState)
\r
321 _viewState.TrackViewState ();
\r
327 protected virtual bool ViewStateIgnoresCase
\r
334 internal bool AutoEventWireup {
\r
335 get { return autoEventWireup; }
\r
336 set { autoEventWireup = value; }
\r
339 internal void SetBindingContainer (bool isBC)
\r
341 bindingContainer = isBC;
\r
344 internal void ResetChildNames ()
\r
346 defaultNumberID = 0;
\r
349 string GetDefaultName ()
\r
351 return "_ctrl" + defaultNumberID++;
\r
354 void NullifyUniqueID ()
\r
357 if (_controls == null)
\r
360 foreach (Control c in _controls)
\r
361 c.NullifyUniqueID ();
\r
364 protected internal virtual void AddedControl (Control control, int index)
\r
366 /* Ensure the control don't have more than 1 parent */
367 if (control._parent != null)
368 control._parent.Controls.Remove (control);
370 control._parent = this;
371 control._page = _page;
372 Control nc = _isNamingContainer ? this : NamingContainer;
375 control._namingContainer = nc;
376 if (control.AutoID == true && control._userId == null)
377 control._userId = nc.GetDefaultName () + "a";
380 if (initing || inited)
381 control.InitRecursive (nc);
383 if (viewStateLoaded || loaded) {
384 if (pendingVS != null) {
385 object vs = pendingVS [index];
387 pendingVS.Remove (index);
388 if (pendingVS.Count == 0)
391 control.LoadViewStateRecursive (vs);
397 control.LoadRecursive ();
400 control.PreRenderRecursiveInternal ();
403 protected virtual void AddParsedSubObject(object obj) //DIT
\r
405 WebTrace.PushContext ("Control.AddParsedSubobject ()");
\r
406 Control c = obj as Control;
\r
407 WebTrace.WriteLine ("Start: {0} -> {1}", obj, (c != null) ? c.ID : String.Empty);
\r
408 if (c != null) Controls.Add(c);
\r
409 WebTrace.WriteLine ("End");
\r
410 WebTrace.PopContext ();
\r
413 protected void BuildProfileTree(string parentId, bool calcViewState)
\r
418 protected void ClearChildViewState ()
423 protected virtual void CreateChildControls() {} //DIT
\r
424 protected virtual ControlCollection CreateControlCollection() //DIT
\r
426 return new ControlCollection(this);
\r
429 protected virtual void EnsureChildControls () //DIT
\r
431 if (ChildControlsCreated == false && !creatingControls) {
\r
432 creatingControls = true;
\r
433 CreateChildControls();
\r
434 ChildControlsCreated = true;
\r
435 creatingControls = false;
\r
439 protected bool IsLiteralContent()
441 if (_controls != null)
442 if (_controls.Count == 1)
443 if (_controls[0] is LiteralControl)
448 public virtual Control FindControl (string id)
\r
450 return FindControl (id, 0);
\r
453 Control LookForControlByName (string id)
\r
458 foreach (Control c in _controls) {
\r
459 if (String.Compare (id, c._userId, true) == 0)
\r
462 if (!c._isNamingContainer && c.HasChildren) {
\r
463 Control child = c.LookForControlByName (id);
\r
472 protected virtual Control FindControl (string id, int pathOffset)
\r
474 EnsureChildControls ();
\r
475 if (_controls == null)
\r
478 Control namingContainer = null;
\r
479 if (!_isNamingContainer) {
\r
480 namingContainer = NamingContainer;
\r
481 if (namingContainer == null)
\r
484 return namingContainer.FindControl (id, pathOffset);
\r
487 int colon = id.IndexOf (':', pathOffset);
\r
489 return LookForControlByName (id.Substring (pathOffset));
\r
491 string idfound = id.Substring (pathOffset, colon - pathOffset);
\r
492 namingContainer = LookForControlByName (idfound);
\r
493 if (namingContainer == null)
\r
496 return namingContainer.FindControl (id, colon + 1);
\r
499 protected virtual void LoadViewState(object savedState)
501 if (savedState != null) {
502 ViewState.LoadViewState (savedState);
503 object o = ViewState ["Visible"];
506 visibleChanged = true;
511 [MonoTODO("Secure?")]
\r
512 protected string MapPathSecure(string virtualPath)
\r
514 string combined = UrlUtils.Combine (TemplateSourceDirectory, virtualPath);
\r
515 return Context.Request.MapPath (combined);
\r
518 protected virtual bool OnBubbleEvent(object source, EventArgs args) //DIT
\r
522 protected virtual void OnDataBinding(EventArgs e) //DIT
\r
524 if (_events != null)
\r
526 EventHandler eh = (EventHandler)(_events[DataBindingEvent]);
\r
527 if (eh != null) eh(this, e);
\r
530 protected virtual void OnInit(EventArgs e) //DIT
\r
532 if (_events != null)
\r
534 EventHandler eh = (EventHandler)(_events[InitEvent]);
\r
535 if (eh != null) eh(this, e);
\r
538 protected virtual void OnLoad(EventArgs e) //DIT
\r
540 if (_events != null)
\r
542 EventHandler eh = (EventHandler)(_events[LoadEvent]);
\r
543 if (eh != null) eh(this, e);
\r
546 protected virtual void OnPreRender(EventArgs e) //DIT
\r
548 if (_events != null)
\r
550 EventHandler eh = (EventHandler)(_events[PreRenderEvent]);
\r
551 if (eh != null) eh(this, e);
\r
554 protected virtual void OnUnload(EventArgs e) //DIT
\r
556 if (_events != null)
\r
558 EventHandler eh = (EventHandler)(_events[UnloadEvent]);
\r
559 if (eh != null) eh(this, e);
\r
563 protected void RaiseBubbleEvent(object source, EventArgs args)
\r
565 Control c = Parent;
\r
566 while (c != null) {
\r
567 if (c.OnBubbleEvent (source, args))
\r
573 protected virtual void Render(HtmlTextWriter writer) //DIT
\r
575 RenderChildren(writer);
\r
578 protected virtual void RenderChildren(HtmlTextWriter writer) //DIT
\r
580 if (_renderMethodDelegate != null)
\r
581 _renderMethodDelegate(writer, this);
\r
582 else if (_controls != null)
\r
583 foreach (Control c in _controls)
\r
584 c.RenderControl(writer);
\r
587 protected virtual object SaveViewState ()
589 if (visibleChanged) {
590 ViewState ["Visible"] = Visible;
591 } else if (_viewState == null) {
595 return _viewState.SaveViewState ();
598 protected virtual void TrackViewState()
\r
600 if (_viewState != null)
\r
601 _viewState.TrackViewState ();
\r
602 _trackViewState = true;
\r
605 public virtual void Dispose()
\r
607 if (_events != null)
\r
609 EventHandler eh = (EventHandler) _events [DisposedEvent];
\r
611 eh(this, EventArgs.Empty);
\r
615 internal bool HasChildren
\r
617 get { return (_controls != null && _controls.Count > 0); }
\r
620 [WebCategory ("FIXME")]
621 [WebSysDescription ("Raised when the contols databound properties are evaluated.")]
\r
622 public event EventHandler DataBinding //DIT
\r
626 Events.AddHandler(DataBindingEvent, value);
\r
630 Events.RemoveHandler(DataBindingEvent, value);
\r
634 [WebSysDescription ("Raised when the contol is disposed.")]
\r
635 public event EventHandler Disposed //DIT
\r
639 Events.AddHandler(DisposedEvent, value);
\r
643 Events.RemoveHandler(DisposedEvent, value);
\r
647 [WebSysDescription ("Raised when the page containing the control is initialized.")]
\r
648 public event EventHandler Init //DIT
\r
652 Events.AddHandler(InitEvent, value);
\r
656 Events.RemoveHandler(InitEvent, value);
\r
660 [WebSysDescription ("Raised after the page containing the control has been loaded.")]
\r
661 public event EventHandler Load //DIT
\r
665 Events.AddHandler(LoadEvent, value);
\r
669 Events.RemoveHandler(LoadEvent, value);
\r
673 [WebSysDescription ("Raised before the page containing the control is rendered.")]
\r
674 public event EventHandler PreRender //DIT
\r
678 Events.AddHandler(PreRenderEvent, value);
\r
682 Events.RemoveHandler(PreRenderEvent, value);
\r
686 [WebSysDescription ("Raised when the page containing the control is unloaded.")]
\r
687 public event EventHandler Unload //DIT
\r
691 Events.AddHandler(UnloadEvent, value);
\r
695 Events.RemoveHandler(UnloadEvent, value);
\r
699 public virtual void DataBind() //DIT
\r
702 bool foundDataItem = false;
704 if (_isNamingContainer && Page != null) {
705 object o = DataBinder.GetDataItem (this, out foundDataItem);
707 Page.PushDataItemContext (o);
713 OnDataBinding (EventArgs.Empty);
719 Page.PopDataItemContext ();
728 void DataBindChildren ()
730 if (_controls == null)
733 foreach (Control c in _controls)
738 public virtual bool HasControls() //DIT
\r
740 if (_controls != null && _controls.Count >0) return true;
\r
744 public void RenderControl(HtmlTextWriter writer)
750 public string ResolveUrl(string relativeUrl)
\r
752 if (relativeUrl == null)
\r
753 throw new ArgumentNullException ("relativeUrl");
\r
755 if (relativeUrl == "")
\r
758 if (relativeUrl [0] == '#')
761 string ts = TemplateSourceDirectory;
\r
762 if (UrlUtils.IsRelativeUrl (relativeUrl) == false || ts == "")
\r
763 return relativeUrl;
\r
765 HttpResponse resp = Context.Response;
\r
766 return resp.ApplyAppPathModifier (UrlUtils.Combine (ts, relativeUrl));
\r
769 [EditorBrowsable (EditorBrowsableState.Advanced)]
\r
770 public void SetRenderMethodDelegate(RenderMethod renderMethod) //DIT
\r
772 _renderMethodDelegate = renderMethod;
\r
775 internal void LoadRecursive()
\r
777 OnLoad (EventArgs.Empty);
\r
778 if (_controls != null) {
\r
779 foreach (Control c in _controls)
\r
780 c.LoadRecursive ();
\r
785 internal void UnloadRecursive(Boolean dispose)
\r
787 if (_controls != null) {
\r
788 foreach (Control c in _controls)
\r
789 c.UnloadRecursive (dispose);
\r
792 OnUnload (EventArgs.Empty);
\r
797 internal void PreRenderRecursiveInternal()
800 EnsureChildControls ();
801 OnPreRender (EventArgs.Empty);
802 if (_controls == null)
805 foreach (Control c in _controls)
806 c.PreRenderRecursiveInternal ();
811 internal void InitRecursive(Control namingContainer)
\r
813 if (_controls != null) {
\r
814 if (_isNamingContainer)
\r
815 namingContainer = this;
\r
817 if (namingContainer != null &&
\r
818 namingContainer._userId == null &&
\r
819 namingContainer.autoID)
\r
820 namingContainer._userId = namingContainer.GetDefaultName () + "b";
\r
822 foreach (Control c in _controls) {
\r
824 c._namingContainer = namingContainer;
\r
825 if (namingContainer != null && c._userId == null && c.autoID)
\r
826 c._userId = namingContainer.GetDefaultName () + "c";
\r
828 c.InitRecursive (namingContainer);
\r
833 OnInit (EventArgs.Empty);
\r
839 internal object SaveViewStateRecursive ()
841 if (!EnableViewState)
844 ArrayList controlList = null;
845 ArrayList controlStates = null;
848 foreach (Control ctrl in Controls) {
849 object ctrlState = ctrl.SaveViewStateRecursive ();
851 if (ctrlState == null)
854 if (controlList == null) {
855 controlList = new ArrayList ();
856 controlStates = new ArrayList ();
859 controlList.Add (idx);
860 controlStates.Add (ctrlState);
863 object thisState = SaveViewState ();
864 if (thisState == null && controlList == null && controlStates == null)
867 return new Triplet (thisState, controlList, controlStates);
870 internal void LoadViewStateRecursive (object savedState)
872 if (!EnableViewState || savedState == null)
875 Triplet savedInfo = (Triplet) savedState;
876 LoadViewState (savedInfo.First);
878 ArrayList controlList = savedInfo.Second as ArrayList;
879 if (controlList == null)
881 ArrayList controlStates = savedInfo.Third as ArrayList;
882 int nControls = controlList.Count;
883 for (int i = 0; i < nControls; i++) {
884 int k = (int) controlList [i];
885 if (k < Controls.Count && controlStates != null) {
886 Control c = Controls [k];
887 c.LoadViewStateRecursive (controlStates [i]);
889 if (pendingVS == null)
890 pendingVS = new Hashtable ();
892 pendingVS [k] = controlStates [i];
896 viewStateLoaded = true;
899 void IParserAccessor.AddParsedSubObject(object obj)
\r
901 AddParsedSubObject(obj);
\r
904 DataBindingCollection IDataBindingsAccessor.DataBindings
\r
908 if(dataBindings == null)
\r
909 dataBindings = new DataBindingCollection();
\r
910 return dataBindings;
\r
914 bool IDataBindingsAccessor.HasDataBindings
\r
918 return (dataBindings!=null && dataBindings.Count>0);
\r
922 internal bool AutoID
\r
924 get { return autoID; }
\r
926 if (value == false && _isNamingContainer)
\r
933 internal void PreventAutoID()
\r
938 protected internal virtual void RemovedControl (Control control)
\r
940 control.UnloadRecursive (false);
\r
941 control._parent = null;
\r
942 control._page = null;
\r
943 control._namingContainer = null;
\r
946 //TODO: I think there are some needed Interface implementations to do here.
949 protected string GetWebResourceUrl (string resourceName)
951 return Page.GetWebResourceUrl (GetType(), resourceName);