【问题标题】:Dynamically loaded user control event subscribing动态加载的用户控件事件订阅
【发布时间】:2011-07-11 19:56:26
【问题描述】:

我很难订阅动态加载的用户控件中的事件。只看我遇到问题的代码可能是最简单的。非常感谢任何帮助。

在父页面我使用这个方法来动态加载用户控件。

 private void LoadMyUserControl(string controlName)
 {
      parent.Controls.Clear();

      // Load the user Control
      UserControl MyControl = (UserControl)LoadControl(ControlName);

      string userControlID = controlName.Split('.')[0];
      MyControl.ID = userControlID.Replace("/","").Replace("~", "");
      Type ucType = MyControl.GetType();

      // Set misc parameters
      PropertyInfo myProp = ucType.GetProperty("MyProp");
      myProp.SetValue(MyControl, "MyVal", null);

      //Dynamically subscribe to user control event
      Type objectType = MyControl.GetType();
      EventInfo objectEventInfo = objectType.GetEvent("updateParent");
      Type objectEventHandlerType = objectEventInfo.EventHandlerType;            
      MethodInfo mi = this.GetType().GetMethod("HandledEvent");
      Delegate del = Delegate.CreateDelegate(objectEventHandlerType, this, mi);
      objectEventInfo.AddEventHandler(this, del);

  }

  public void HandledEvent (Object sender, EventArgs e)
  {

  }

我的用户控件有一个像这样的简单公共事件

  public partial class MyUserControl1 : System.Web.UI.UserControl
  {
         public int MyProp { get; set; }
         public event EventHandler updateParent;
  }

我得到的错误出现在 ObjectEventInfo.AddEventHandler 行上,指出“对象与目标类型不匹配。”

再次提前感谢您的帮助。

【问题讨论】:

  • 我想你会想要将你的 UserControl 转换为 MyUserControl1 与 UserControl。
  • 当您可以创建一个具有事件引用的通用接口 IControl、转换为接口类型并以这种方式引用它时,为什么还要使用反射呢?这样,多个UC的满足签名,但可以引用它强类型...
  • 我很欣赏这一点,但我真的在努力磨练我有限的反思技巧。难道不能通过反射来做到这一点吗?

标签: c# asp.net user-controls


【解决方案1】:

解决方案 #1: 创建一个通用接口。

// IParentControlUpdater.cs
namespace AspNetUserControlDynamicEvent {
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    interface IParentControlUpdater {
        event EventHandler<EventArgs> UpdateParent;
    }
}

// DynamicUserControl.ascx.cs
namespace AspNetUserControlDynamicEvent {
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;

    public partial class DynamicUserControl : System.Web.UI.UserControl, IParentControlUpdater {
        protected void Page_Load(object sender, EventArgs e) { }

        #region IParentControlUpdater Members

        public event EventHandler<EventArgs> UpdateParent;

        #endregion
    }
}

// Default.aspx.cs
namespace AspNetUserControlDynamicEvent {
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;

    public partial class _Default : System.Web.UI.Page {
        protected void Page_Load(object sender, EventArgs e) { }

        private void LoadMyUserControl(string controlName) {
            UserControl control = (UserControl)LoadControl(controlName);

            // Do some stuff 

            ((IParentControlUpdater)control).UpdateParent += new EventHandler<EventArgs>(control_UpdateParent);
        }

        private void control_UpdateParent(object sender, EventArgs e) {
            throw new NotImplementedException();
        }
    }
}

解决方案 #2: 创建一个基类。 创建一个基本用户控件类(例如 DynamicUserControlBase)。

// DynamicUserControlBase.ascx.cs
namespace AspNetUserControlDynamicEvent {
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;

    public partial class DynamicUserControlBase : System.Web.UI.UserControl {
        protected void Page_Load(object sender, EventArgs e) { }

        // Base event
        public event System.EventHandler<System.EventArgs> UpdateParent;
    }
}

然后在您的用户控件中,您要动态创建和订阅 updateParent 事件:

// DynamicUserControl.ascx.cs
namespace AspNetUserControlDynamicEvent {
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;

    public partial class DynamicUserControl : DynamicUserControlBase {
        protected void Page_Load(object sender, EventArgs e) { }
    }
}

注意它是如何从 DynamicUserControlBase 继承的。现在,对于您的 LoadMyUserControl 方法:

private void LoadMyUserControl(string controlName) {
    DynamicUserControlBase control = (DynamicUserControlBase)LoadControl(controlName);

    // Do some stuff     

    control.UpdateParent += new EventHandler<EventArgs>(HandledEvent);
}

private void HandledEvent(object sender, EventArgs e) {
    throw new NotImplementedException();
}

但是,如果您只使用一种类型的控件,您可以轻松地将 LoadControl 上的装箱更改为:

WebUserControl1 control = (WebUserControl1)LoadControl(controlName); // example

但似乎您可能正在考虑加载许多不同类型的用户控件,因此第一个解决方案应该可以正常工作。

至于您对反射的关注,试试这个:

Type type = MyControl.GetType();
EventInfo eventInfo = type.GetEvent("UpdateParent");
EventHandler handler = new EventHandler(HandledEvent);
eventInfo.AddEventHandler(MyControl, handler);

【讨论】:

  • 这一切都说得通,感谢您的帮助,但出于好奇,难道不能使用反射来做到这一点吗?我真的很想知道我在这里做错了什么。
  • Reflection 对于性能来说是杂乱无章的,所以我一般来说。当有明显的替代方案时,我不推荐它,但为了学习,我会在靠近计算机(家)时进一步研究它)
  • 在底部更新了我的答案。
【解决方案2】:

如果您想获得一个通用的解决方案,您可以使用您的属性和事件创建一个抽象的用户控件类。然后 MyUserControl1 可以继承这个抽象的用户控件。在您的加载方法中,您可以转换为抽象用户控件并以更简单的方式使用它。所以你可以创建一些其他的用户控件。

【讨论】:

  • 正在回答包含代码的相同方法。似乎是适合他的解决方案。
  • 我认为这很常见。我以同样的方式使用我的控件。但是你需要为你的努力付出代价;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-09-07
  • 2012-08-06
  • 2010-11-08
  • 1970-01-01
  • 1970-01-01
  • 2011-05-17
相关资源
最近更新 更多