简体   繁体   中英

Binding to events in dynamically loaded user controls

I am constructing a test project to demonstrate (to me) how to dynamically load user controls. Everything works except the wiring of the control to notify the parent that something has happened. The problem is with the line that tries to connect the event in the user control to the event handler in the parent page. The "NotifyParentEvent" event is not visible and the compiler barfs on it (the event is not defined in System.Web.UI.Control). I have tried using UserControl instead of Control, but to no avail.

Control control = Page.LoadControl(SavedControlVirtualPath);
if (control != null)
{
    control.ID = control.GetType().Name;
>>>>>    control.NotifyParentEvent += new EventHandler(UserControlNotificationHandler);
    controlPlaceholder.Controls.Add(control);
}

Code behind for User Control:

public partial class UserControls_WebUserControl1 : System.Web.UI.UserControl
{
    public event CommandEventHandler NotifyParentEvent;

    private void NotifyParent(string message)
    {
        if (NotifyParentEvent != null)
        {
            CommandEventArgs e = new CommandEventArgs("Control1 Action", message);
            NotifyParentEvent(this, e);
        }
    }
}

Parent Page:

public partial class _Default : System.Web.UI.Page
{
    private string SavedControlVirtualPath
    {
        get {return (ViewState["savedControlPath"] == null || (string)ViewState["savedControlPath"] == string.Empty) 
                ? null : (string)ViewState["savedControlPath"]; }
        set { ViewState["savedControlPath"] = value; }
    }

    private void ReloadControl()
    {
        controlPlaceholder.Controls.Clear();
        if (SavedControlVirtualPath != null)
        {
            Control control = Page.LoadControl(SavedControlVirtualPath);
            if (control != null)
            {
                // Gives the control a unique ID. It is important to ensure
                // the page working properly. Here we use control.GetType().Name
                // as the ID.
                control.ID = control.GetType().Name;
                control.NotifyParentEvent += new EventHandler(UserControlNotificationHandler); <== THIS LINE WON'T COMPILE
                controlPlaceholder.Controls.Add(control);
            }
        }
    }

    private void UserControlNotificationHandler(object sender, CommandEventArgs e)
    {
        //  ???
    }

    protected void Page_Init(object sender, EventArgs e)
    {
        lblLastEvent.Text += "Page_Init<br />";
        LoadUserControls();
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        lblLastEvent.Text += string.Format("{0} on main page<br />", (this.IsPostBack) ? "Postback" : "Page_Load");
        ReloadControl();
    }

    protected void rblControlSelector_Changed(object sender, EventArgs e)
    {
        lblLastEvent.Text += "rblControlSelector_Changed<br />";
        LoadUserControls();
    }

    private void LoadUserControls()
    {
        Label lbl = new Label();
        controlPlaceholder.Controls.Clear();
        switch (rblControlSelector.SelectedValue)
        {
            case "0":
                lblLastEvent.Text = "Unload/Clear<br />";
                SavedControlVirtualPath = "";
                break;

            case "1":
                lblLastEvent.Text += "Adding control #1<br />";
                SavedControlVirtualPath = "~/UserControls/WebUserControl1.ascx";
                break;

            case "2":
                lblLastEvent.Text += "Adding control #2<br />";
                SavedControlVirtualPath = "~/UserControls/WebUserControl2.ascx";
                break;

            case "3":
                lblLastEvent.Text += "Adding control #3<br />";
                SavedControlVirtualPath = "~/UserControls/WebUserControl3.ascx";
                break;

        }
        if (!string.IsNullOrEmpty(SavedControlVirtualPath))
        {
            ReloadControl();
        }
    }
}

Option 1

You need to cast you control to a type that implements the NotifyParentEvent event in order to attach the event handler. Basically, in your ReloadControl method, replace this line of code:

control.NotifyParentEvent += new EventHandler(UserControlNotificationHandler);

with the following:

if(control is UserControls_WebUserControl1) 
{
    (control as UserControls_WebUserControl1).NotifyParentEvent += new EventHandler(UserControlNotificationHandler);
}

Option 2

A more generic approach would be to create an interface and check if the dynamic control implements that interface.

Create the interface:

interface INotifyParent
{
    event CommandEventHandler NotifyParentEvent;
}

Implement the interface:

public partial class UserControls_WebUserControl1 : System.Web.UI.UserControl, INotifyParent
{
    public event CommandEventHandler NotifyParentEvent;

    private void NotifyParent(string message)
    {
        if (NotifyParentEvent != null)
        {
            CommandEventArgs e = new CommandEventArgs("Control1 Action", message);
            NotifyParentEvent(this, e);
        }
    }
}

Check if the dynamic control implements the interface:

if(control is INotifyParent) 
{
    (control as INotifyParent).NotifyParentEvent += new EventHandler(UserControlNotificationHandler);
}

Try casting the control to it's proper type before you add the eventhandler.

I'm not sure this will work, but try casting using the dynamic type rather than Control.

aka

dynamic control = Page.LoadControl(SavedControlVirtualPath);

This code assumes you are using .NET 4.0

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM