【问题标题】:Binding to events in dynamically loaded user controls绑定到动态加载的用户控件中的事件
【发布时间】:2011-07-21 22:40:50
【问题描述】:

我正在构建一个测试项目来演示(向我)如何动态加载用户控件。一切正常,除了控件的接线以通知父母发生了什么事。问题在于尝试将用户控件中的事件连接到父页面中的事件处理程序的行。 “NotifyParentEvent”事件是不可见的,并且编译器会在它上面出错(该事件未在 System.Web.UI.Control 中定义)。我曾尝试使用 UserControl 而不是 Control,但无济于事。

Control control = Page.LoadControl(SavedControlVirtualPath);
if (control != null)
{
    control.ID = control.GetType().Name;
>>>>>    control.NotifyParentEvent += new EventHandler(UserControlNotificationHandler);
    controlPlaceholder.Controls.Add(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);
        }
    }
}

父页面:

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();
        }
    }
}

【问题讨论】:

  • 在下面编辑了我的问题,如果有帮助请告诉我

标签: c# dynamic user-controls event-handling


【解决方案1】:

选项 1

您需要将控件强制转换为实现 NotifyParentEvent 事件的类型才能附加事件处理程序。基本上,在你的ReloadControl 方法中,替换这行代码:

control.NotifyParentEvent += new EventHandler(UserControlNotificationHandler);

以下内容:

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

选项 2

更通用的方法是创建一个接口并检查动态控件是否实现了该接口。

创建接口:

interface INotifyParent
{
    event CommandEventHandler NotifyParentEvent;
}

实现接口:

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);
        }
    }
}

检查动态控件是否实现接口:

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

【讨论】:

  • 我会试试这个,但是这个解决方案要求我知道每个控件的类名。我需要一个通用的解决方案,它将动态确定在 NotifyParentHandler 事件中是否定义,如果是,则将其连接起来。
  • 然后您应该创建一个公开事件的接口并让控件实现该接口。通过这种方式,您可以转换为接口类型而不是具体的控件类型。使用实现事件的基类也可能有意义,这样您就不必在每个控件中复制代码。
  • 感谢 Vassili 和 Tim Stall 的文章 (4guysfromrolla.com/articles/110304-1.aspx),我得到了这个工作。做了一些调整,但如果有人想要源代码,请告诉我。
  • 控制作为 INotifyParent 对我来说是一个很好的解决方案。 @BobJones 你能评论你的代码 sn-p 吗?
【解决方案2】:

在添加事件处理程序之前,尝试将控件转换为正确的类型。

我不确定这是否可行,但请尝试使用动态类型而不是 Control 进行投射。

又名

dynamic control = Page.LoadControl(SavedControlVirtualPath);

此代码假定您使用的是 .NET 4.0

【讨论】:

  • 鉴于它是一个动态加载的控件,我不知道它是正确的类型。你能给我一个你正在考虑的代码的例子吗?我怀疑这可能需要我还不明白的“反思”。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-08
  • 2011-09-18
  • 1970-01-01
  • 2012-08-06
  • 2015-04-06
  • 1970-01-01
相关资源
最近更新 更多