views:

1360

answers:

3

I am adding dynamically controls to page by using LoadControl and Controls.Add. I need somehow to wrap Init and Load event handlers of this loaded controls into my code. So it should be such order of events SomeMyCode() -> Control.Init() -> AnotherMyCode() and the same for Load SomeMyCode() -> Control.Load() -> AnotherMyCode().
My idea was to Get List of Control's event handlers for Init and Load events and add first and last event handers with code I should to run. But I cannot figure out how to do this.

A: 

BTW why I cannot get field "EventLoad"? I can see it in Framework sources but cannot get it :-(

Control ctrl = this.LoadControl("WebUserControl1.ascx");

FieldInfo fieldInfo = typeof(Control).GetType().GetField("EventLoad", BindingFlags.NonPublic | BindingFlags.Static);
horseman
Because of extra GetType call. Should be:typeof(Control).GetField("EventLoad", BindingFlags.NonPublic | BindingFlags.Static);
horseman
You mean GetEvent("EventLoad"), events are not fields.
justin.m.chase
2 just in case: No that is OK. See code below.
horseman
+1  A: 

You cannot forcibly inject an event handler in front of other handlers already subscribed to an event. If you need method A to be called first, then you'll need to subscribe A first.


Re your comment, that is incredibly hacky. First, you can't even rely on an event having a delegate-field backer; it can be an EventHandlerList or other - which don't nevessarily expose handy hooks short of reversing the removal.

Second (and more important), it breaks every rule of encapsulation.

In general, if you want to be first, the best approach is to override the OnFoo() method. The second-best is to subscribe first.

Marc Gravell
Yes I know. But I can use GetInovocationList to obtain all delegates and then add them in needed order
horseman
Yes, this approach is not so clean but in any case it works. I think that disallowing to get this events in more strict way it's bad design form MS.
horseman
@Horseman - and I think that the design is *correct* to be strict about this. The "bad design", frankly, is your choosing to disregard encapsulation. So be it...
Marc Gravell
A: 

Here is draft of working solution:

protected void Page_Load(object sender, EventArgs e)
{
  Control ctrl = this.LoadControl("WebUserControl1.ascx");
  PropertyInfo propertyInfo = typeof(Control).GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
  EventHandlerList eventHandlerList = propertyInfo.GetValue(ctrl, new object[]{}) as EventHandlerList;
  FieldInfo fieldInfo = typeof(Control).GetField("EventLoad", BindingFlags.NonPublic | BindingFlags.Static);

  if(fieldInfo == null)
    return;

  object eventKey = fieldInfo.GetValue(ctrl);
  Delegate eventHandler = eventHandlerList[eventKey] as Delegate;

  foreach(EventHandler item in eventHandler.GetInvocationList()) {
    ctrl.Load -= item;
  }

  ctrl.Load += ctrl_Load;
  foreach (EventHandler item in eventHandler.GetInvocationList()){
    ctrl.Load += item;
  }
  ctrl.Load += ctrl_Load;

  this.Controls.Add(ctrl);
}

void ctrl_Load(object sender, EventArgs e)
{
  //throw new NotImplementedException();
}

}

Question is closed. Thank you all for answers!

horseman