From the outside of a control, is it possible to find out what stage of the Page LifeCycle (Init, Load, PreRender etc), a particular control or page is up to?
For example, in pseudo code:
if myControl.CurrentLifeCycle == Lifecycle.Init { do something }
I'm afraid there is no builtin function to check in what Page-Lifecycle phase a Page is. It is also difficult to add this functionality without handling all events in the Page itself, because some events are protected. Therefore you could also inherit the LifeCycleListener-class from Control, add it in the constructor to the page listening and override all events.
If you only need the public "phases" PreInit,Init,Load,DataBinding,PreRender,Unload,Disposed
have a look at following approach(VB.Net, but i think you'll get the idea):
Public Enum LifeCyclePhase AfterPreInit AfterInit AfterLoad AfterDataBinding AfterPreRender AfterUnload AfterDisposed End Enum Public Interface ITrackingLifeCycle ReadOnly Property GetLifeCycleListener() As LifeCycleListener End Interface Public Class LifeCycleListener Public Sub New(ByVal ctrl As Control) Me._PageListening = ctrl.Page AddListener() End Sub Private _CurrentPhase As LifeCyclePhase Private _PageListening As Page Public ReadOnly Property CurrentPhase() As LifeCyclePhase Get Return _CurrentPhase End Get End Property Public ReadOnly Property PageListening() As Page Get Return _PageListening End Get End Property Private Sub AddListener() AddHandler _PageListening.PreInit, AddressOf PreInit AddHandler _PageListening.Init, AddressOf Init AddHandler _PageListening.Load, AddressOf Load AddHandler _PageListening.DataBinding, AddressOf DataBinding AddHandler _PageListening.PreRender, AddressOf PreRender AddHandler _PageListening.Unload, AddressOf Unload AddHandler _PageListening.Disposed, AddressOf Disposed End Sub Private Sub PreInit(ByVal sender As Object, ByVal e As EventArgs) Me._CurrentPhase = LifeCyclePhase.AfterPreInit End Sub Private Sub Init(ByVal sender As Object, ByVal e As EventArgs) Me._CurrentPhase = LifeCyclePhase.AfterInit End Sub Private Sub Load(ByVal sender As Object, ByVal e As EventArgs) Me._CurrentPhase = LifeCyclePhase.AfterLoad End Sub Private Sub DataBinding(ByVal sender As Object, ByVal e As EventArgs) Me._CurrentPhase = LifeCyclePhase.AfterDataBinding End Sub Private Sub PreRender(ByVal sender As Object, ByVal e As EventArgs) Me._CurrentPhase = LifeCyclePhase.AfterPreRender End Sub Private Sub Unload(ByVal sender As Object, ByVal e As EventArgs) Me._CurrentPhase = LifeCyclePhase.AfterUnload End Sub Private Sub Disposed(ByVal sender As Object, ByVal e As EventArgs) Me._CurrentPhase = LifeCyclePhase.AfterDisposed End Sub End Class
The handler in this class are called after the handler in the page itself, so if you f.e. check the CurrentPhase in Page.Init you'll get PreInit. Therefor i have called this phase AfterPreInit.
Partial Public Class _Default Inherits System.Web.UI.Page Implements ITrackingLifeCycle Private lcl As New LifeCycleListener(Me) Public ReadOnly Property GetLifeCycleListener() As LifeCycleListener Implements ITrackingLifeCycle.GetLifeCycleListener Get Return lcl End Get End Property
You can now check the lifecycle-phase everywhere, even without a reference to a control via HttpContext.Current:
Public Class FooClass Public Shared Sub Foo() If Not (HttpContext.Current Is Nothing OrElse HttpContext.Current.Handler Is Nothing) Then If TypeOf HttpContext.Current.CurrentHandler Is ITrackingLifeCycle Then Dim page As ITrackingLifeCycle = DirectCast(HttpContext.Current.CurrentHandler, ITrackingLifeCycle) Dim phase As LifeCyclePhase = page.GetLifeCycleListener.CurrentPhase End If End If End Sub End Class
This is neither tested sufficiently nor used by myself and certainly improvable, but maybe it helps you in your current situation.
I think what you try to achieve is conceptually wrong because you are thinking at the page events as page state. The page can’t be at “OnInit/OnLoad/…” state just because it’s an event.
What do you need it for? maybe we could suggest you a better approach to achieve your goal.
As far as I understand the page lifecycle, you can't do it. Basically, Page class is the guy that has to raise events in a specific order. There is nothing in built that will tell the stage of processing. But in order to something, you can create a property and set up this property in different stages of processing.
I found out there is actually an internal property of the Page class that does just what I am looking for: it is an enum called ControlState:
internal enum ControlState { Constructed, FrameworkInitialized, ChildrenInitialized, Initialized, ViewStateLoaded, Loaded, PreRendered }
I believe it is possible to access internal members in C#4, see here