Avatar of Tom Knowlton
Tom Knowlton
Flag for United States of America asked on

Late binding to an event - please provide source code solution, no links.

I have some dynamic controls that I am loading in at runtime.  These controls have events they can raise, which I will NOT know about ahead of time, but I will have methods with matching signatures.  What I want to accomplish is to tie those events to the handlers.

Look for my comments in the code below to see what method I want to attach to.  I don't want to FIRE the event...I just want to become a listener.


When you reply...please provide working C# source code ONLY!!   Please....NO LINKS TO ARTICLES OR WEBSITES!


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.IO;
using System.Reflection;

namespace Campus_Webstore
{
    public partial class SiteManager : System.Web.UI.Page
    {
        protected void Page_PreInit(object sender, System.EventArgs e)
        {
            this.MasterPageFile = "~/contentfiles/" + Page.StyleSheetTheme + "/TCSSite.Master";
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            if (!Page.IsPostBack)
            {
                GlobalMethods.InitControlList();


                string layout = "";

                if (Request.QueryString["layout"] != null)
                {
                    layout = Request.QueryString["layout"] as string;
                }
                else
                {
                    layout = "default";
                }

                DisplayLayout(layout);

            }
           
        }

        private void DisplayLayout(string layout)
        {
            GlobalMethods.divlayoutgencontrols.Clear();

            StreamReader sr = new StreamReader(Server.MapPath("~/CustomLayouts/") + Page.StyleSheetTheme + "/" + layout + ".xml");
            string filecontents = sr.ReadToEnd();
            string countstr = GlobalMethods.ExtractValueFromXML(filecontents, "<count>");
            int count = Convert.ToInt32(countstr);
            string tempGUID = "";
            string settings = "";
            string[] settingsarray = new string[count];

            for (int i = 1; i <= count; i++)
            {
                settings = GlobalMethods.ExtractValueFromXML(filecontents, "<" + i.ToString() + ">");
                settingsarray = settings.Split(',');

                Control c = LoadControl("~/UserControls/" + settingsarray[0] + ".ascx");

                Type controlType = c.GetType();
                BindingFlags myBindingFlags = BindingFlags.Instance | BindingFlags.Public;
                EventInfo[] myEvents = controlType.GetEvents(myBindingFlags);

                for(int j = 0; j < myEvents.Count(); j++)
                {
                    string eventName = myEvents.ElementAt(j).Name;
                    if (eventName == "NameAvailabilityEvent")
                    {
                        //Delegate d = Delegate.CreateDelegate(myEvents.ElementAt(j).EventHandlerType, this,myEvents.ElementAt(j).Name);
                        //c.GetType().GetEvent(eventName).AddEventHandler(c, d);






                        //btn is "c"

                        EventInfo evt = c.GetType().GetEvent(myEvents.ElementAt(j).Name);
                        MethodInfo handler = GetType().GetMethod("SomeHandler");




//////////////////////////////   HERE IS WHERE THE BINDING MIGHT TAKE PLACE  /////////////////////////////////





                        evt.AddEventHandler(c, Delegate.CreateDelegate(
                                evt.EventHandlerType, this, handler));

                    }
                }              

                c.Visible = true;
                tempGUID = Guid.NewGuid().ToString();
                c.ID = settingsarray[0] + tempGUID + i.ToString();

                GlobalMethods.divlayoutgencontrols.Add(c);
            }

            foreach (Control c in GlobalMethods.divlayoutgencontrols)
            {
                sitemanagercontrolsdiv.Controls.Add(c);
            }


            Master.CalcCartTotal();
            Master.ShowCat();
            Master.DisplayUser();

        }



////////////////////   I WANT TO BIND THE EVENT TO THIS METHOD  /////////////////////////////////////////

        public void SomeHandler(bool wasavailable)
        {
       //     create_new_user.ShowRotatingArrow(true);

            if (wasavailable)
            {
                //LabelResultMessage.Text = "That username is available.";
                //ButtonClosePanelMessage.Visible = true;
                //PanelMessage.Visible = true;
            }
            else
            {
                //LabelResultMessage.Text = "That username is already taken.";
                //ButtonClosePanelMessage.Visible = true;
                //PanelMessage.Visible = true;

            }

          //  create_new_user.ShowRotatingArrow(false);
        }
    }
}

Open in new window

ASP.NETC#

Avatar of undefined
Last Comment
Bob Learned

8/22/2022 - Mon
Bob Learned

Tom,

One possibility, off the top of my head, would be to use reflection, as shown in this MSDN article:

How to: Hook Up a Delegate Using Reflection
http://msdn.microsoft.com/en-us/library/ms228976.aspx

Assembly assem = Assembly.GetExecutingAssembly();

Type tExForm = assem.GetType("ExampleForm");
Object exFormAsObj = Activator.CreateInstance(tExForm);

EventInfo evClick = tExForm.GetEvent("Click");
Type tDelegate = evClick.EventHandlerType;

MethodInfo miHandler = 
    typeof(Example).GetMethod("LuckyHandler", 
        BindingFlags.NonPublic | BindingFlags.Instance);

Delegate d = Delegate.CreateDelegate(tDelegate, this, miHandler);

MethodInfo addHandler = evClick.GetAddMethod();
Object[] addHandlerArgs = { d };
addHandler.Invoke(exFormAsObj, addHandlerArgs);

Open in new window


Tom Knowlton

ASKER
Hi TLO,

For some reason the event does not fire.

Can you take a look at my current code?

You should be able to create a small project using the information I give below that will duplicate this problem.  I've been staring at this for so long I don't think I can be very useful, meaning, I have tried and failed at getting this to work over a period of days, trying every bit of advice and permuation I can glean from websites.

What is the difference between what the MSDN article is doing and what I'm doing?

Thanks from a very frustrated programmer.  :)


MARKUP FOR THE USER CONTROL (.ascx):

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="TestRaiseEvent.ascx.cs" Inherits="Campus_Webstore.TestRaiseEvent" %>
<asp:Button ID="Button1" runat="server" Text="Raise an Event now" onclick="Button1_Click" />

CODE-BEHIND FOR THE USER CONTROL (.ascx):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace Campus_Webstore
{   
    public delegate void ButtonWasClicked (string message);
   
    public partial class TestRaiseEvent : System.Web.UI.UserControl
    {
        public event ButtonWasClicked ButtonClickedEvent;
              
        protected void Page_Load(object sender, EventArgs e)
        {
        }

        protected void Button1_Click(object sender, EventArgs e)
        {
            if (ButtonClickedEvent != null)
            {
                ButtonClickedEvent("some message");
            }         
        }
    }
}






Then, here is the main webform that will attempt to load the control above programmatically and discover and subscribe to the event that is raises:



MARKUP FOR THE WEB FORM  (.aspx)  [uses a master page]:

<%@ Page Title="" Language="C#" AutoEventWireup="true" CodeBehind="SiteManager.aspx.cs" Inherits="Campus_Webstore.SiteManager" %>


<%@ MasterType TypeName="Campus_Webstore.SiteWideMaster.TCSMasterBase" %>


<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
<div id="sitemanagercontrolsdiv" runat="server">  
</div>
</asp:Content>






CODE-BEHIND FOR THE WEB FORM (.aspx)


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.IO;
using System.Reflection;



//The control collection cannot be modified during
//DataBind,
//Init,
//Load,
//PreRender or
//Unload phases.

namespace Campus_Webstore
{
    public partial class SiteManager : System.Web.UI.Page
    {
        protected void Page_PreInit(object sender, System.EventArgs e)
        {
            this.MasterPageFile = "~/contentfiles/" + Page.StyleSheetTheme + "/TCSSite.Master";

            GlobalMethods.InitControlList();


            string layout = "";

            if (Request.QueryString["layout"] != null)
            {
                layout = Request.QueryString["layout"] as string;
            }
            else
            {
                layout = "default";
            }

            LoadControls(layout);

        }
             
        protected void Page_Load(object sender, EventArgs e)
        {
            //if (!Page.IsPostBack)
            //{
            //    GlobalMethods.InitControlList();


            //    string layout = "";

            //    if (Request.QueryString["layout"] != null)
            //    {
            //        layout = Request.QueryString["layout"] as string;
            //    }
            //    else
            //    {
            //        layout = "default";
            //    }

            //    LoadControls(layout);
            //}       

            Master.CalcCartTotal();
            Master.ShowCat();
            Master.DisplayUser();

        }


        //The control collection cannot be modified during
        //DataBind,
        //Init,
        //Load,
        //PreRender or
        //Unload phases.

        protected void Page_LoadComplete(object sender, EventArgs e)
        {         
                sitemanagercontrolsdiv.Controls.Clear();

                try
                {
                    if (GlobalMethods.divlayoutgencontrols != null)
                    {
                        foreach (Control c in GlobalMethods.divlayoutgencontrols)
                        {
                            sitemanagercontrolsdiv.Controls.Add(c);
                        }
                    }
                }
                catch (Exception eee)
                {
                    string a = eee.Message;
                }
           
        }


        private void LoadControls(string layout)
        {
           
            StreamReader sr = new StreamReader(Server.MapPath("~/CustomLayouts/") + Page.StyleSheetTheme + "/" + layout + ".xml");
            string filecontents = sr.ReadToEnd();
            string countstr = GlobalMethods.ExtractValueFromXML(filecontents, "<count>");
            int count = Convert.ToInt32(countstr);
            string tempGUID = "";
            string settings = "";
            string[] settingsarray = new string[count];

            for (int i = 1; i <= count; i++)
            {
                settings = GlobalMethods.ExtractValueFromXML(filecontents, "<" + i.ToString() + ">");
                settingsarray = settings.Split(',');

                Control c = LoadControl("~/UserControls/" + settingsarray[0] + ".ascx");
                                           
                Type controlType = c.GetType();
               
                BindingFlags myBindingFlags = BindingFlags.Instance | BindingFlags.Public;
                EventInfo[] myEvents = controlType.GetEvents(myBindingFlags);

                for (int j = 0; j < myEvents.Count(); j++)
                {
                    string eventName = myEvents.ElementAt(j).Name;
                    if (eventName == "ButtonClickedEvent")
                    {
                        EventInfo evt = c.GetType().GetEvent(myEvents.ElementAt(j).Name);
                        MethodInfo handler = typeof(SiteManager).GetMethod("SomeHandler");
                        Delegate del = Delegate.CreateDelegate(evt.EventHandlerType, this, handler);
                        evt.AddEventHandler(c, del);                       
                    }
                }

                c.Visible = true;
                tempGUID = Guid.NewGuid().ToString();
                c.ID = settingsarray[0] + tempGUID + i.ToString();

                GlobalMethods.divlayoutgencontrols.Add(c);
            }         
        }

        public void SomeHandler(string message)
        {
            // do something
        }
    }
}



HERE ARE THE CONTENTS OF default.xml, a file which is read-in at runtime:

<count>1</count>
<1>TestRaiseEvent</1>

Open in new window

Bob Learned

We are interested in the below section--what does tracing tell you?  Are you getting events from myEvents?  Are you getting a reference to the "SomeHandler" method?

              BindingFlags myBindingFlags = BindingFlags.Instance | BindingFlags.Public;
                EventInfo[] myEvents = controlType.GetEvents(myBindingFlags);

                for (int j = 0; j < myEvents.Count(); j++)
                {
                    string eventName = myEvents.ElementAt(j).Name;
                    if (eventName == "ButtonClickedEvent")
                    {
                        EventInfo evt = c.GetType().GetEvent(myEvents.ElementAt(j).Name);
                        MethodInfo handler = typeof(SiteManager).GetMethod("SomeHandler");
                        Delegate del = Delegate.CreateDelegate(evt.EventHandlerType, this, handler);
                        evt.AddEventHandler(c, del);                       
                    }
                }

Open in new window

Experts Exchange is like having an extremely knowledgeable team sitting and waiting for your call. Couldn't do my job half as well as I do without it!
James Murphy
Bob Learned

What framework version are you using with the web site?
Tom Knowlton

ASKER
Bob,

I think it is 4.0XXXX

 about vs
Tom Knowlton

ASKER
We are interested in the below section--what does tracing tell you?  Are you getting events from myEvents?  Are you getting a reference to the "SomeHandler" method?

=================================

How do I find this out?

Trace dumps a bunch of stuff at the bottom of the screen, right?
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
Tom Knowlton

ASKER
As far as getting Events from myEvents..........the answer is definitely YES:


 my Events collection
Tom Knowlton

ASKER
It is this event I want to handle from that list:

{Campus_Webstore.ButtonWasClicked ButtonClickedEvent}
Bob Learned

1) You don't have the Ultimate edition, so Intellitrace is out

2) Trace does dump a lot of information, and is not useful

3) The words I should have used are "step debugging"--or stepping through the code, and inspecting important values.

4) If your web site is configured for 4.0, then you might be able to use the "dynamic" keyword when referencing the control.

5) I have not tried "dynamic" in an ASP.NET 4 web site, but theoretically it might work.

C# 4.0 dynamic Keyword
http://spradip.wordpress.com/2011/02/07/c-4-0-dynamic-keyword/
Your help has saved me hundreds of hours of internet surfing.
fblack61
Tom Knowlton

ASKER
As far as a reference to the "SomeHandler" method....does this help?



 handler
Tom Knowlton

ASKER
After looking at my screenshots of my debugger / watch window ---   do you still think the dynamic keyword is the issue?
Bob Learned

I see the event reference, and the event handler method reference, so I don't see anything that explains why the event is not raised.

protected void Button1_Click(object sender, EventArgs e)
        {
            if (ButtonClickedEvent != null)
            {
                ButtonClickedEvent("some message");
            }         
        }

Open in new window


Are you reaching the line that triggers the ButtonClickEvent?  In other words, is ButtonClickedEvent delegate not null?
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
Tom Knowlton

ASKER
I am a bit fuzzy on how the AddEventHandler call is preserved across a postback...

If you have to create the controls EVERY TIME a postback happens...then how does an event ever manage to fire and do anything?
Tom Knowlton

ASKER
Are you reaching the line that triggers the ButtonClickEvent?  In other words, is ButtonClickedEvent delegate not null?

=================================

I am happy to see you ask this.....for this has been my question as well!!!!

I set a breakpoint on the if(ButtonClickedEvent !- null) and the code execution NEVER stops there in the debugger
Bob Learned

This sounds like a good time to review the page life cycle, since if you don't re-add dynamic controls to the page at the right time in the cycle, then event handlers will not be re-attached correctly when the page posts back.
This is the best money I have ever spent. I cannot not tell you how many times these folks have saved my bacon. I learn so much from the contributors.
rwheeler23
Tom Knowlton

ASKER
If it helps, here is me running the code and clicking the button on the control

 knowlton-487649.flv
Tom Knowlton

ASKER
This sounds like a good time to review the page life cycle, since if you don't re-add dynamic controls to the page at the right time in the cycle, then event handlers will not be re-attached correctly when the page posts back.

==================================

For 500 points, I would like some help with this please.  What are your recommendations?

You have seen my code...what changes would I make?
Bob Learned

I try to help where I can.

1) I see DisplayLayout(layout); in the Page_Load event.

2) In the DisplayLayout method, you are loading the user control:

Control c = LoadControl("~/UserControls/" + settingsarray[0] + ".ascx");

3) Take a look at the page life cycle:

ASP.NET Page Life Cycle Overview
http://msdn.microsoft.com/en-us/library/ms178472.aspx 

Page Life Cycle
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
Tom Knowlton

ASKER
Where did you get that image?

Is that some sort of tool you are using?
Bob Learned

Snagit by TechSmith
http://www.techsmith.com/snagit/
Tom Knowlton

ASKER
No...not the screencapture....

The image itself....is that a screenshot of a tool you were using?
Experts Exchange has (a) saved my job multiple times, (b) saved me hours, days, and even weeks of work, and often (c) makes me look like a superhero! This place is MAGIC!
Walt Forbes
Bob Learned

Scroll down this page to see the image

ASP.NET Page Life Cycle Overview
http://msdn.microsoft.com/en-us/library/ms178472.aspx 
Tom Knowlton

ASKER
Here is a complete test project so you can:

-follow along with what I am trying
-make recommendations based on what you observe while debugging

It seems to me this should help you help me solve this.

Here is the link to the download page:

http://ube.dev.campuswebstore.mobi/dloadfile.htm
Bob Learned

I would try moving the DisplayLayout call to the Page_Init method.
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
Tom Knowlton

ASKER
With all due respect, just throwing a bunch of stuff at me about page life-cycle is not going to help me solve this, Bob.  Help me fix this first....then I think it will be obvious to me how the page life cycle ties in.

I have tried reloading the controls in page init in the past and I would get complaints about modifying the collection:


 //The control collection cannot be modified during
        //DataBind,
        //Init,
        //Load,
        //PreRender or
        //Unload phases.


So I am at a loss as to how a better understanding of the page lifecycle will help me.
Tom Knowlton

ASKER
>>>>>>>I would try moving the DisplayLayout call to the Page_Init method.

==============================

Tried it.......the event still does not fire




protected void Page_Init(object sender, System.EventArgs e)
        {
            string layout = "";

            if (Request.QueryString["layout"] != null)
            {
                layout = Request.QueryString["layout"] as string;
            }
            else
            {
                layout = "default";
            }


            if (!Page.IsPostBack)
            {
                GlobalMethods.InitControlList();
                LoadControls(layout);              
            }
            
        }

Open in new window

Tom Knowlton

ASKER
In the meantime....I have begun reading the article.


I will TRY to understand the page life-cycle better....but right now I am in GET IT DONE mode.....I would rather get this working...then worry about how and why later on!!!!!!!


From the first paragraph:

When an ASP.NET page runs, the page goes through a life cycle in which it performs a series of processing steps. These include initialization, instantiating controls, restoring and maintaining state, running event handler code, and rendering. It is important for you to understand the page life cycle so that you can write code at the appropriate life-cycle stage for the effect you intend.

This descibes my current dilemna pretty well....so yes, I see the value in understanding the page life-cycle better.  Touche!!!!
All of life is about relationships, and EE has made a viirtual community a real community. It lifts everyone's boat
William Peck
Tom Knowlton

ASKER
The article makes sense to me, but I am not sure how dynamically added controls work, since they seem to be a bit different from registered controls:

If controls are created dynamically at run time or declaratively within templates of data-bound controls, their events are initially not synchronized with those of other controls on the page. For example, for a control that is added at run time, the Init and Load events might occur much later in the page life cycle than the same events for controls created declaratively. Therefore, from the time that they are instantiated, dynamically added controls and controls in templates raise their events one after the other until they have caught up to the event during which it was added to the Controls collection.


I don't really understand this.....I really need some help to get this working...please!
Bob Learned

I really don't like the complexity that comes with dynamic controls, and I certainly don't like it with user controls (unlike custom web controls).

Try this:

Befuddling Error: "The control collection cannot be modified during DataBind, Init, Load, PreRender or Unload phases."
http://iformattable.blogspot.com/2007/07/befuddling-error-control-collection.html

My understanding is that you can modify down, not up, in the controls hierarchy. In other words, if you want to add a control dynamically to your parent, the parent needs to have a place to put it. The solution is to add a PlaceHolder control to the parent, then add your controls dynamically to that PlaceHolder.

Tom Knowlton

ASKER
I've not been using a placeholder, I've been using a div.  Does it matter?
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
Tom Knowlton

ASKER
I really don't like the complexity that comes with dynamic controls, and I certainly don't like it with user controls (unlike custom web controls).

======================

I've gone to great lengths to make my little demo as UN complex as possible:

http://ube.dev.campuswebstore.mobi/dloadfile.htm

Perhaps you should tinker with it and see if anything jumps out at you!!!!
Bob Learned

I would try the PlaceHolder, since it is a different beast than a <div>.  I will not have much time to download, and play with anything right now, as I am working on a production issue of my own.
Tom Knowlton

ASKER
>>>>I would try the PlaceHolder, since it is a different beast than a <div>.  

===========================

I will!!!!!!


>>>>>>I will not have much time to download, and play with anything right now, as I am working on a production issue of my own.

==================

I sympathize!
I started with Experts Exchange in 2004 and it's been a mainstay of my professional computing life since. It helped me launch a career as a programmer / Oracle data analyst
William Peck
Tom Knowlton

ASKER
I wish I could say that using a Placeholder control to house the dynamic controls made a difference, but it made no difference.
Bob Learned

I would like to assume that you put the PlaceHolder onto the parent page that loads the control, but I really should check...
Tom Knowlton

ASKER
Here is the markup for the parent page:


<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebApplication2._Default" %>

<%@ Register src="TestRaiseEvent.ascx" tagname="TestRaiseEvent" tagprefix="uc1" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
<uc1:TestRaiseEvent ID="TestRaiseEvent77" runat="server" />
<br />
<br />
<br />
<br />

<asp:PlaceHolder ID="sitemanagercontrolsdiv" runat="server">
</asp:PlaceHolder>

   
    </form>
</body>
</html>

Open in new window

Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
Tom Knowlton

ASKER
I would like to assume that you put the PlaceHolder onto the parent page that loads the control, but I really should check...
==============================

Wow, you really don't like me much, do you?

LOL
Bob Learned

I really should check every time I want to make an assumption, disregarding any personalities...and, you modified the code to add to load into the PlaceHolder, and not the page...
Tom Knowlton

ASKER
>>>>I really should check every time I want to make an assumption, disregarding any personalities...

Um...  "okay"   :)


One way to avoid having to guess is to provide an example of the markup (like I just did) so that there is no confusion as to where the placeholder tag is located.  :)
Experts Exchange is like having an extremely knowledgeable team sitting and waiting for your call. Couldn't do my job half as well as I do without it!
James Murphy
Bob Learned

I bet you didn't change anything, other than the type:

GlobalMethods.divlayoutgencontrols.Add(c);
Tom Knowlton

ASKER
I bet you didn't change anything, other than the type:

GlobalMethods.divlayoutgencontrols.Add(c);

=============================================


GlobalMethods.divlayoutgencontrols.Add(c);

is a List<> of controls.  It was my approach to preserve the controls across a postback.


I am not sure I am understanding your concern.
Bob Learned

How is the user control added to the page or PlaceHolder?
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
Tom Knowlton

ASKER
>>>How is the user control added to the page or PlaceHolder?

It is done here:


GlobalMethods.divlayoutgencontrols.Add(c);

at the bottom of LoadControls.
Tom Knowlton

ASKER
Actually....that was adding to the global static List< > of controls.

I apologize.


It is added to the placeholder here:

  private void AddControlsFromList()
        {
            sitemanagercontrolsdiv.Controls.Clear();

            try
            {
                if (GlobalMethods.divlayoutgencontrols != null)
                {
                    foreach (Control c in GlobalMethods.divlayoutgencontrols)
                    {
                        sitemanagercontrolsdiv.Controls.Add(c);
                    }
                }
            }
            catch (Exception eee)
            {
                string a = eee.Message;
            }
        }





Keep in mind that my SMALL demo is now different than my original web page code I first posted.


It is the DEMO that I have been making changes to.
Tom Knowlton

ASKER
sitemanagercontrolsdiv    IS    a placeholder, even though the name is the same as the old <div>
Your help has saved me hundreds of hours of internet surfing.
fblack61
Bob Learned

Where is "AddControlsFromList" called from?  You are clearing the PlaceHolder control, and then re-adding, and I don't believe that is necessary.

sitemanagercontrolsdiv.Controls.Clear();
Tom Knowlton

ASKER
It is called in Page Load and Page Load Complete.

If I don't do this, the control will disappear (the one that is added dynamically) on postback.

    protected void Page_Load(object sender, EventArgs e)
        {            
            Master.CalcCartTotal();
            Master.ShowCat();
            Master.DisplayUser();

            AddControlsFromList();
        }


        //The control collection cannot be modified during 
        //DataBind, 
        //Init, 
        //Load, 
        //PreRender or 
        //Unload phases.
        
        protected void Page_LoadComplete(object sender, EventArgs e)
        {
            AddControlsFromList();
        }

Open in new window

Bob Learned

Why is it called from 2 methods?
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
Tom Knowlton

ASKER
>>>>Why is it called from 2 methods?

I don't know.

I commented out the one in Page_LoadComplete and it made no difference.  The dynamic control still shows up after a postback.

So...I guess the second call was not needed.  


BUT ---  the event still does not fire after making that change.
ASKER CERTIFIED SOLUTION
Bob Learned

Log in or sign up to see answer
Become an EE member today7-DAY FREE TRIAL
Members can start a 7-Day Free trial then enjoy unlimited access to the platform
Sign up - Free for 7 days
or
Learn why we charge membership fees
We get it - no one likes a content blocker. Take one extra minute and find out why we block content.
Not exactly the question you had in mind?
Sign up for an EE membership and get your own personalized solution. With an EE membership, you can ask unlimited troubleshooting, research, or opinion questions.
ask a question
Bob Learned

In order to use the "dynamic" keyword, I needed to add a reference to the Microsoft.CSharp.dll to my web application project.
Tom Knowlton

ASKER
In order to use the "dynamic" keyword, I needed to add a reference to the Microsoft.CSharp.dll to my web application project.

============================

Good work!!   I will check this out in a few minutes.


Now -- I don't think I really spelled this out.....and if I need to ask another question on this topic I can.....but the whole KEY to this is Reflection.  I am not sure I saw any reflection being used in your solution.


I want to be able to bind events to handlers ... but in my parent I will have pre-made handlers that will match the events being raised.  However, I will not know which events the control has until runtime.


I am trying to make a more flexible dynamic app than what most developers code for.


I will see how workable your solution is with these requirements and report back here.


Thank you,


Tom
This is the best money I have ever spent. I cannot not tell you how many times these folks have saved my bacon. I learn so much from the contributors.
rwheeler23
Bob Learned

I saw that you were looping through the events, looking for event names like NameAvailabilityEvent or ButtonClickedEvent, which sounded like it lends itself to dynamic, because you know that you are looking for a specific event.  
Tom Knowlton

ASKER
I am having a difficult time getting the project to run.

I have included references to Microsoft.CSharp.dll and it still will not compile
Tom Knowlton

ASKER
Here is what I get at compile time:

 sys core
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
Tom Knowlton

ASKER
Any ideas?
Bob Learned

I would make sure that the project is configured for 4.0 framework.


Snapshot.png
Tom Knowlton

ASKER
>>>>I would make sure that the project is configured for 4.0 framework.

=========================


That was what I needed.  I was configured for 3.5.


So....that got your demo working.


But I am still faced with the problem of getting it to work with Reflection.

Should I ask about Reflection in another question, or keep this question open?

Are you able to help with Reflection questions?
Experts Exchange has (a) saved my job multiple times, (b) saved me hours, days, and even weeks of work, and often (c) makes me look like a superhero! This place is MAGIC!
Walt Forbes
SOLUTION
Log in to continue reading
Log In
Sign up - Free for 7 days
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
Tom Knowlton

ASKER
Thank you for your help on this Bob.  You were the only one who showed up here and gave it a try.
Bob Learned

Here is the equivalent reflection code (tested):

        protected void Page_Load(object sender, EventArgs e)
        {
            Control control = this.LoadControl("WebUserControl1.ascx");

            Type type = typeof(_Default);

            EventInfo eventInfo = control.GetType().GetEvent("Test");

            MethodInfo methodInfo = type.GetMethod("Control_Test", 
                BindingFlags.NonPublic | BindingFlags.Instance);

            Delegate eventDelegate = Delegate.CreateDelegate(eventInfo.EventHandlerType, this, methodInfo);
            
            eventInfo.AddEventHandler(control, eventDelegate);                       
            
            this.PlaceHolder1.Controls.Add(control);
        }

        private void Control_Test(object sender, EventArgs e)
        {
            this.Label1.Text = "Button clicked";
        }

Open in new window