[asp.net] Fix for bug #685267. ClientScriptManager generates correct post-back event...
[mono.git] / mcs / class / System.Web / System.Web.UI / TemplateControl.jvm.cs
index 922efde212c4856ddb86a215d7cf71ed0080d31b..28a3f0f79701368095398228423a5c8e96c451a4 100644 (file)
@@ -33,15 +33,16 @@ using System.Web.J2EE;
 using System.Xml;
 using vmw.common;
 using System.Web.Util;
+using System.Collections.Generic;
 
 namespace System.Web.UI {
 
        public abstract class TemplateControl : Control, INamingContainer
        {
-               static object abortTransaction = new object ();
-               static object commitTransaction = new object ();
-               static object error = new object ();
-               static string [] methodNames = { "Page_Init",
+               static readonly object abortTransaction = new object ();
+               static readonly object commitTransaction = new object ();
+               static readonly object error = new object ();
+               static readonly string [] methodNames = { "Page_Init",
 #if NET_2_0
                                                 "Page_PreInit",
                                                 "Page_PreLoad",
@@ -54,18 +55,57 @@ namespace System.Web.UI {
                                                 "Page_DataBind",
                                                 "Page_PreRender",
                                                 "Page_Disposed",
-                                                "Page_Error",
                                                 "Page_Unload",
+                                                "Page_Error",
                                                 "Page_AbortTransaction",
                                                 "Page_CommitTransaction" };
 
+               static readonly object [] EventKeys = {
+                                                Control.InitEvent,
+#if NET_2_0
+                                                Page.PreInitEvent,
+                                                Page.PreLoadEvent,
+                                                Page.LoadCompleteEvent,
+                                                Page.PreRenderCompleteEvent,
+                                                Page.SaveStateCompleteEvent,
+                                                Page.InitCompleteEvent,
+#endif
+                                               Control.LoadEvent,
+                                               Control.DataBindingEvent,
+                                               Control.PreRenderEvent,
+                                               Control.DisposedEvent,
+                                               Control.UnloadEvent,
+                                               error,
+                                               abortTransaction,
+                                               commitTransaction
+               };
+
+               enum LifeCycleEvent
+               {
+                       Init,
+#if NET_2_0
+                       PreInit,
+                       PreLoad,
+                       LoadComplete,
+                       PreRenderComplete,
+                       SaveStateComplete,
+                       InitComplete,
+#endif
+                       Load,
+                       DataBinding,
+                       PreRender,
+                       Disposed,
+                       Unload,
+                       Error,
+                       AbortTransaction,
+                       CommitTransaction
+               }
+
                const BindingFlags bflags = BindingFlags.Public |
                                                BindingFlags.NonPublic |
                                                BindingFlags.Instance;
-               static readonly Type [] NoParams = new Type [0];
 
-               private static string hashTableMutex = "lock"; //used to sync access ResourceHash property
-               private byte [] GetResourceBytes (Type type)
+               byte [] GetResourceBytes (Type type)
                {
                        Hashtable table = (Hashtable) AppDomain.CurrentDomain.GetData ("TemplateControl.RES_BYTES");
                        if (table == null) {
@@ -73,7 +113,7 @@ namespace System.Web.UI {
                        }
                        return (byte []) table [type];
                }
-               private void SetResourceBytes (Type type, byte [] bytes)
+               void SetResourceBytes (Type type, byte [] bytes)
                {
                        Hashtable table = (Hashtable) AppDomain.CurrentDomain.GetData ("TemplateControl.RES_BYTES");
                        if (table == null) {
@@ -84,7 +124,7 @@ namespace System.Web.UI {
                        return;
                }
 
-               private Hashtable ResourceHash
+               Hashtable ResourceHash
                {
                        get
                        {
@@ -101,7 +141,7 @@ namespace System.Web.UI {
                        }
                }
 
-               private string CachedString (Type type, int offset, int size)
+               string CachedString (Type type, int offset, int size)
                {
                        CacheKey key = new CacheKey (type, offset, size);
 
@@ -162,14 +202,14 @@ namespace System.Web.UI {
 
                sealed class EventMethodMap
                {
-                       public EventMethodMap (EventInfo Event, MethodInfo Method, bool NoParameters)
+                       public EventMethodMap (LifeCycleEvent EventKeyIndex, MethodInfo Method, bool NoParameters)
                        {
-                               this.Event = Event;
+                               this.EventKeyIndex = EventKeyIndex;
                                this.Method = Method;
                                this.NoParameters = NoParameters;
                        }
 
-                       public readonly EventInfo Event;
+                       public readonly LifeCycleEvent EventKeyIndex;
                        public readonly MethodInfo Method;
                        public readonly bool NoParameters;
                }
@@ -200,7 +240,25 @@ namespace System.Web.UI {
                                typeof (object),
                                typeof (EventArgs) };
 
-                               foreach (string methodName in methodNames) {
+                LifeCycleEvent[] _pageEvents = new LifeCycleEvent[] { 
+                    LifeCycleEvent.PreInit,
+                    LifeCycleEvent.PreLoad,
+                    LifeCycleEvent.LoadComplete,
+                    LifeCycleEvent.PreRenderComplete,
+                    LifeCycleEvent.SaveStateComplete,
+                    LifeCycleEvent.InitComplete
+                };
+                List<LifeCycleEvent> pageEvents = new List<LifeCycleEvent>(_pageEvents);
+
+                bool isPage = Page.GetType().IsAssignableFrom(GetType());
+
+                               for (int i = 0; i < methodNames.Length; i++) {
+                    
+                    // Don't look for page-only events in non-page controls.
+                    if (!isPage && pageEvents.Contains((LifeCycleEvent)i))
+                        continue;
+
+                                       string methodName = methodNames [i];
                                        MethodInfo method;
                                        bool noParams = false;
                                        Type type = GetType ();
@@ -217,7 +275,7 @@ namespace System.Web.UI {
                                        if (method == null) {
                                                type = GetType ();
                                                do {
-                                                       method = type.GetMethod (methodName, bflags, null, NoParams, null);
+                                                       method = type.GetMethod (methodName, bflags, null, Type.EmptyTypes, null);
                                                        if (method != null) {
                                                                noParams = true;
                                                                break;
@@ -233,22 +291,7 @@ namespace System.Web.UI {
                                        if (method.ReturnType != voidType)
                                                continue;
 
-                                       int pos = methodName.IndexOf ("_");
-                                       string eventName = methodName.Substring (pos + 1);
-                                       EventInfo evt = GetType ().GetEvent (eventName);
-                                       if (evt == null) {
-                                               /* This should never happen */
-                                               continue;
-                                       }
-
-                                       eventMethodList.Add (new EventMethodMap (evt, method, noParams));
-#if ONLY_1_1
-                               if (method.DeclaringType != type) {
-                                       if (!method.IsPublic && !method.IsFamilyOrAssembly &&
-                                           !method.IsFamilyAndAssembly && !method.IsFamily)
-                                               continue;
-                               }
-#endif
+                                       eventMethodList.Add (new EventMethodMap ((LifeCycleEvent) i, method, noParams));
                                }
                                // We copy to not lock
 
@@ -258,12 +301,64 @@ namespace System.Web.UI {
                        }
 
                        foreach (EventMethodMap eventMethod in eventMethodList) {
-                               if (eventMethod.NoParameters) {
-                                       NoParamsInvoker npi = new NoParamsInvoker (this, eventMethod.Method);
-                                       eventMethod.Event.AddEventHandler (this, npi.FakeDelegate);
-                               }
-                               else {
-                                       eventMethod.Event.AddEventHandler (this, Delegate.CreateDelegate (typeof (EventHandler), this, eventMethod.Method));
+                               EventHandler handler = eventMethod.NoParameters ?
+                                       new NoParamsInvoker (this, eventMethod.Method).FakeDelegate :
+                                       (EventHandler)Delegate.CreateDelegate (typeof (EventHandler), this, eventMethod.Method);
+
+                               object eventKey = EventKeys [(int) eventMethod.EventKeyIndex];
+
+                               Delegate existing = Events [eventKey];
+                               if (existing != null && handler.Equals(existing))
+                                       continue;
+
+                               switch (eventMethod.EventKeyIndex) {
+                               case LifeCycleEvent.Init:
+                                       Init += handler;
+                                       break;
+#if NET_2_0
+                               case LifeCycleEvent.PreInit:
+                                       ((Page)this).PreInit += handler;
+                                       break;
+                               case LifeCycleEvent.PreLoad:
+                                       ((Page) this).PreLoad += handler;
+                                       break;
+                               case LifeCycleEvent.LoadComplete:
+                                       ((Page) this).LoadComplete += handler;
+                                       break;
+                               case LifeCycleEvent.PreRenderComplete:
+                                       ((Page) this).PreRenderComplete += handler;
+                                       break;
+                               case LifeCycleEvent.SaveStateComplete:
+                                       ((Page) this).SaveStateComplete += handler;
+                                       break;
+                               case LifeCycleEvent.InitComplete:
+                                       ((Page) this).InitComplete += handler;
+                                       break;
+#endif
+                               case LifeCycleEvent.Load:
+                                       Load += handler;
+                                       break;
+                               case LifeCycleEvent.DataBinding:
+                                       DataBinding += handler;
+                                       break;
+                               case LifeCycleEvent.PreRender:
+                                       PreRender += handler;
+                                       break;
+                               case LifeCycleEvent.Disposed:
+                                       Disposed += handler;
+                                       break;
+                               case LifeCycleEvent.Unload:
+                                       Unload += handler;
+                                       break;
+                               case LifeCycleEvent.Error:
+                                       Error += handler;
+                                       break;
+                               case LifeCycleEvent.AbortTransaction:
+                                       AbortTransaction += handler;
+                                       break;
+                               case LifeCycleEvent.CommitTransaction:
+                                       CommitTransaction += handler;
+                                       break;
                                }
                        }
                }
@@ -469,7 +564,7 @@ namespace System.Web.UI {
                        }
                }
 
-               sealed private class CacheKey
+               sealed class CacheKey
                {
                        readonly Type _type;
                        readonly int _offset;
@@ -517,6 +612,10 @@ namespace System.Web.UI {
                        }
                }
 
+               internal override TemplateControl TemplateControlInternal {
+                       get { return this; }
+               }
+
                protected internal object Eval (string expression)
                {
                        return DataBinder.Eval (Page.GetDataItem (), expression);