Merge branch 'cecil-light'
[mono.git] / mcs / class / System.Web.Extensions / System.Web.UI / UpdatePanel.cs
1 //
2 // UpdatePanel.cs
3 //
4 // Authors:
5 //   Igor Zelmanovich <igorz@mainsoft.com>
6 //   Marek Habersack <grendel@twistedcode.net>
7 //
8 // (C) 2007 Mainsoft, Inc.  http://www.mainsoft.com
9 // (C) 2007-2010 Novell, Inc (http://novell.com/)
10 //
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using System;
33 using System.Collections.Generic;
34 using System.Text;
35 using System.ComponentModel;
36 using System.Security.Permissions;
37 using System.IO;
38
39 namespace System.Web.UI
40 {
41         [DesignerAttribute ("System.Web.UI.Design.UpdatePanelDesigner, System.Web.Extensions.Design, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")]
42         [DefaultPropertyAttribute ("Triggers")]
43         [ParseChildrenAttribute (true)]
44         [PersistChildrenAttribute (false)]
45         [AspNetHostingPermissionAttribute (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
46         [AspNetHostingPermissionAttribute (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
47         public class UpdatePanel : Control
48         {
49                 sealed class SingleChildControlCollection : ControlCollection
50                 {
51                         public SingleChildControlCollection (Control owner)
52                                 : base (owner)
53                         {}
54
55                         internal void AddInternal (Control child)
56                         {
57                                 base.Add (child);
58                         }
59                         
60                         public override void Add (Control child)
61                         {
62                                 throw GetNoChildrenException ();
63                         }
64
65                         public override void AddAt (int index, Control child)
66                         {
67                                 throw GetNoChildrenException ();
68                         }
69
70                         public override void Clear ()
71                         {
72                                 throw GetNoChildrenException ();
73                         }
74
75                         public override void Remove (Control value)
76                         {
77                                 throw GetNoChildrenException ();
78                         }
79
80                         public override void RemoveAt (int index)
81                         {
82                                 throw GetNoChildrenException ();
83                         }
84                         
85                         InvalidOperationException GetNoChildrenException ()
86                         {
87                                 return new InvalidOperationException ("The Controls property of UpdatePanel with ID '" + Owner.ID + "' cannot be modified directly. To change the contents of the UpdatePanel modify the child controls of the ContentTemplateContainer property.");
88                         }
89                 }
90                 
91                 ITemplate _contentTemplate;
92                 Control _contentTemplateContainer;
93                 UpdatePanelUpdateMode _updateMode = UpdatePanelUpdateMode.Always;
94                 bool _childrenAsTriggers = true;
95                 bool _requiresUpdate;
96                 bool _inPartialRendering;
97                 UpdatePanelTriggerCollection _triggers;
98                 UpdatePanelRenderMode _renderMode = UpdatePanelRenderMode.Block;
99                 ScriptManager _scriptManager;
100                 Control cachedParent;
101                 UpdatePanel parentPanel;
102                 bool parentPanelChecked;
103                 
104                 UpdatePanel ParentPanel {
105                         get {
106                                 Control parent = Parent;
107                                 if (cachedParent == parent && parentPanelChecked)
108                                         return parentPanel;
109
110                                 cachedParent = parent;
111                                 parentPanel = FindParentPanel (parent);
112
113                                 return parentPanel;
114                         }
115                 }
116                 
117                 [Category ("Behavior")]
118                 [DefaultValue (true)]
119                 public bool ChildrenAsTriggers {
120                         get {
121                                 return _childrenAsTriggers;
122                         }
123                         set {
124                                 _childrenAsTriggers = value;
125                         }
126                 }
127
128                 [TemplateInstance (TemplateInstance.Single)]
129                 [PersistenceMode (PersistenceMode.InnerProperty)]
130                 [Browsable (false)]
131                 public ITemplate ContentTemplate {
132                         get {
133                                 return _contentTemplate;
134                         }
135                         set {
136                                 _contentTemplate = value;
137                         }
138                 }
139
140                 [Browsable (false)]
141                 public Control ContentTemplateContainer {
142                         get {
143                                 if (_contentTemplateContainer == null) {
144                                         _contentTemplateContainer = CreateContentTemplateContainer ();
145                                         ((SingleChildControlCollection) Controls).AddInternal (_contentTemplateContainer);
146                                 }
147                                 return _contentTemplateContainer;
148                         }
149                 }
150
151                 public override sealed ControlCollection Controls {
152                         get { return base.Controls; }
153                 }
154
155                 [Browsable (false)]
156                 public bool IsInPartialRendering {
157                         get { return _inPartialRendering; }
158                 }
159
160                 [Category ("Layout")]
161                 public UpdatePanelRenderMode RenderMode {
162                         get {
163                                 return _renderMode;
164                         }
165                         set {
166                                 _renderMode = value;
167                         }
168                 }
169
170                 protected internal virtual bool RequiresUpdate {
171                         get {
172                                 return UpdateMode == UpdatePanelUpdateMode.Always || _requiresUpdate || AnyTriggersFired ();
173                         }
174                 }
175
176                 internal ScriptManager ScriptManager {
177                         get {
178                                 if (_scriptManager == null) {
179                                         _scriptManager = ScriptManager.GetCurrent (Page);
180                                         if (_scriptManager == null)
181                                                 throw new InvalidOperationException (String.Format ("The control with ID '{0}' requires a ScriptManager on the page. The ScriptManager must appear before any controls that need it.", ID));
182                                 }
183                                 return _scriptManager;
184                         }
185                 }
186
187                 [MergableProperty (false)]
188                 [DefaultValue ("")]
189                 [PersistenceMode (PersistenceMode.InnerProperty)]
190                 [Category ("Behavior")]
191                 public UpdatePanelTriggerCollection Triggers {
192                         get {
193                                 if (_triggers == null)
194                                         _triggers = new UpdatePanelTriggerCollection (this);
195                                 return _triggers;
196                         }
197                 }
198
199                 bool AnyTriggersFired ()
200                 {
201                         if (_triggers == null || _triggers.Count == 0)
202                                 return false;
203
204                         foreach (UpdatePanelTrigger trigger in _triggers)
205                                 if (trigger.HasTriggered ())
206                                         return true;
207
208                         return false;
209                 }
210                 
211                 [Category ("Behavior")]
212                 [DefaultValueAttribute (UpdatePanelUpdateMode.Always)]
213                 public UpdatePanelUpdateMode UpdateMode {
214                         get {
215                                 return _updateMode;
216                         }
217                         set {
218                                 _updateMode = value;
219                         }
220                 }
221
222                 // Used by nested panels (see bug #542441)
223                 ScriptManager.AlternativeHtmlTextWriter RenderChildrenWriter { get; set; }
224                 
225                 protected virtual Control CreateContentTemplateContainer ()
226                 {
227                         return new Control ();
228                 }
229
230                 protected override sealed ControlCollection CreateControlCollection ()
231                 {
232                         return new SingleChildControlCollection (this);
233                 }
234
235                 protected internal virtual void Initialize ()
236                 {
237                         int tcount = _triggers != null ? _triggers.Count : 0;
238                         if (tcount == 0 || !ScriptManager.SupportsPartialRendering)
239                                 return;
240                         
241                         for (int i = 0; i < tcount; i++)
242                                 _triggers [i].Initialize ();
243                 }
244
245                 protected override void OnInit (EventArgs e) {
246                         base.OnInit (e);
247
248                         ScriptManager.RegisterUpdatePanel (this);
249                         if (ParentPanel != null)
250                                 ScriptManager.RegisterChildUpdatePanel (this);
251                         
252                         if (ContentTemplate != null)
253                                 ContentTemplate.InstantiateIn (ContentTemplateContainer);
254                 }
255
256                 protected override void OnLoad (EventArgs e) {
257                         base.OnLoad (e);
258
259                         Initialize ();
260                 }
261
262                 protected override void OnPreRender (EventArgs e) {
263                         base.OnPreRender (e);
264
265                         if (UpdateMode == UpdatePanelUpdateMode.Always && !ChildrenAsTriggers)
266                                 throw new InvalidOperationException (String.Format ("ChildrenAsTriggers cannot be set to false when UpdateMode is set to Always on UpdatePanel '{0}'", ID));
267                 }
268
269                 protected override void OnUnload (EventArgs e) {
270                         base.OnUnload (e);
271                 }
272
273                 protected override void Render (HtmlTextWriter writer) {
274                         writer.AddAttribute (HtmlTextWriterAttribute.Id, ClientID);
275                         if (RenderMode == UpdatePanelRenderMode.Block)
276                                 writer.RenderBeginTag (HtmlTextWriterTag.Div);
277                         else
278                                 writer.RenderBeginTag (HtmlTextWriterTag.Span);
279                         RenderChildren (writer);
280                         writer.RenderEndTag ();
281                 }
282
283                 UpdatePanel FindParentPanel (Control parent)
284                 {
285                         parentPanelChecked = true;
286                         while (parent != null) {
287                                 UpdatePanel panel = parent as UpdatePanel;
288                                 if (panel != null)
289                                         return panel;
290                                 
291                                 parent = parent.Parent;
292                         }
293
294                         return null;
295                 }
296                 
297                 protected override void RenderChildren (HtmlTextWriter writer)
298                 {
299                         RenderChildrenWriter = null;
300                         
301                         if (IsInPartialRendering) {
302                                 ScriptManager.AlternativeHtmlTextWriter altWriter = writer as ScriptManager.AlternativeHtmlTextWriter;
303                                 if (altWriter == null)
304                                         altWriter = writer.InnerWriter as ScriptManager.AlternativeHtmlTextWriter;
305                                 
306                                 if (altWriter == null) {
307                                         UpdatePanel parentPanel = ParentPanel;
308                                         if (parentPanel != null)
309                                                 altWriter = parentPanel.RenderChildrenWriter;
310                                 }
311
312                                 if (altWriter == null)
313                                         throw new InvalidOperationException ("Internal error. Invalid writer object.");
314
315                                 // Used by nested panels (see bug #542441)
316                                 RenderChildrenWriter = altWriter;
317                                 try {
318                                         HtmlTextWriter responseOutput = altWriter.ResponseOutput;
319                                         StringBuilder sb = new StringBuilder ();
320                                         HtmlTextWriter w = new HtmlTextWriter (new StringWriter (sb));
321                                         base.RenderChildren (w);
322                                         w.Flush ();
323                                         if (sb.Length > 0) {
324                                                 if (ParentPanel != null)
325                                                         writer.Write (sb.ToString ());
326                                                 else
327                                                         ScriptManager.WriteCallbackPanel (responseOutput, this, sb);
328                                         }
329                                 } finally {
330                                         RenderChildrenWriter = null;
331                                 }
332                         } else
333                                 base.RenderChildren (writer);
334                 }
335
336                 internal void SetInPartialRendering (bool setting)
337                 {
338                         _inPartialRendering = setting;
339                 }
340                 
341                 public void Update ()
342                 {
343                         if (UpdateMode == UpdatePanelUpdateMode.Always)
344                                 throw new InvalidOperationException ("The Update method can only be called on UpdatePanel with ID '" + ID + "' when UpdateMode is set to Conditional.");
345                         
346                         _requiresUpdate = true;
347                 }
348         }
349 }