ascx用户控件中的事件处理

时间:2008-09-18 14:10:02

标签: c# asp.net

将事件从用户控件传递到父控件/页面的最佳做法是什么?我想做类似的事情:

MyPage.aspx:
<asp:Content ID="Content1" ContentPlaceHolderID="MainContentPlaceholder" runat="server">
  <uc1:MyUserControl ID="MyUserControl1" runat="server" 
     OnSomeEvent="MyUserControl_OnSomeEvent" />

MyUserControl.ascx.cs:
public partial class MyUserControl: UserControl
{
    public event EventHandler SomeEvent;
....
   private void OnSomething()
    {
        if (SomeEvent!= null)
            SomeEvent(this, EventArgs.Empty);
    }

问题是什么是最佳做法?

3 个答案:

答案 0 :(得分:6)

您可能希望在父级中订阅的控件上创建一个事件。有关示例,请参阅OdeToCode

以下是关于长寿的文章:

某些用户控件完全是自包含的,例如,显示当前股票报价的用户控件不需要与页面上的任何其他内容进行交互。其他用户控件将包含要回发的按钮。虽然可以从包含页面订阅按钮单击事件,但这样做会破坏一些面向对象的封装规则。更好的想法是在用户控件中发布一个事件,以允许任何感兴趣的各方处理该事件。

这种技术通常被称为“事件冒泡”,因为事件可以继续穿过图层,从底部(用户控件)开始,也可能到达顶层(页面),就像气泡向上移动香槟玻璃

对于初学者,让我们创建一个带有按钮的用户控件。

<%@ Control Language="c#" AutoEventWireup="false" 
    Codebehind="WebUserControl1.ascx.cs" 
    Inherits="aspnet.eventbubble.WebUserControl1" 
    TargetSchema="http://schemas.microsoft.com/intellisense/ie5"
%>
<asp:Panel id="Panel1" runat="server" Width="128px" Height="96px">
    WebUserControl1 
    <asp:Button id="Button1" Text="Button" runat="server"/>
</asp:Panel>

用户控件的代码如下所示。

public class WebUserControl1 : System.Web.UI.UserControl
{
   protected System.Web.UI.WebControls.Button Button1;
   protected System.Web.UI.WebControls.Panel Panel1;

   private void Page_Load(object sender, System.EventArgs e)
   {
      Response.Write("WebUserControl1 :: Page_Load <BR>");
   }

   private void Button1_Click(object sender, System.EventArgs e)
   {
      Response.Write("WebUserControl1 :: Begin Button1_Click <BR>");
      OnBubbleClick(e);
      Response.Write("WebUserControl1 :: End Button1_Click <BR>");
   }

   public event EventHandler BubbleClick;

   protected void OnBubbleClick(EventArgs e)
   {
      if(BubbleClick != null)
      {
         BubbleClick(this, e);
      }
   }           

   #region Web Form Designer generated code
   override protected void OnInit(EventArgs e)
   {
      InitializeComponent();
      base.OnInit(e);
   }

   private void InitializeComponent()
   {
      this.Button1.Click += new System.EventHandler(this.Button1_Click);
      this.Load += new System.EventHandler(this.Page_Load);

   }
   #endregion

}

用户控件指定声明委托的公共事件(BubbleClick)。任何对BubbleClick事件感兴趣的人都可以添加一个EventHandler方法,以便在事件触发时执行 - 就像用户控件在Button触发Click事件时添加一个EventHandler一样。

在OnBubbleClick事件中,我们首先检查是否有人附加到事件(BubbleClick!= null),然后我们可以通过调用BubbleClick,传递EventArgs参数并设置用户控件来调用所有事件处理方法(this)作为事件发件人。请注意,我们还使用Response.Write来跟踪执行流程。

ASPX页面现在可以让用户控件正常工作。

<%@ Register TagPrefix="ksa" 
    TagName="BubbleControl" 
    Src="WebUserControl1.ascx" 
%>
<%@ Page language="c#" Codebehind="WebForm1.aspx.cs" 
    AutoEventWireup="false" Inherits="aspnet.eventbubble.WebForm1" 
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
    <HEAD>
        <title>WebForm1</title>
    </HEAD>
    <body MS_POSITIONING="GridLayout">
        <form id="Form1" method="post" runat="server">
            <ksa:BubbleControl id="BubbleControl" runat="server" />
        </form>
    </body>
</HTML>

在页面背后的代码中。

public class WebForm1 : System.Web.UI.Page
{
   protected WebUserControl1 BubbleControl;

   private void Page_Load(object sender, System.EventArgs e)
   {
      Response.Write("WebForm1 :: Page_Load <BR>");
   }

   #region Web Form Designer generated code
   override protected void OnInit(EventArgs e)
   {
      InitializeComponent();
      base.OnInit(e);
   }

   private void InitializeComponent()
   {    
      this.Load += new System.EventHandler(this.Page_Load);
      BubbleControl.BubbleClick += new EventHandler(WebForm1_BubbleClick);
   }
   #endregion

   private void WebForm1_BubbleClick(object sender, EventArgs e)
   {
      Response.Write("WebForm1 :: WebForm1_BubbleClick from " + 
                     sender.GetType().ToString() + "<BR>");         
   }
}

请注意,父页面只需要在InitializeComponent方法中添加事件处理程序。当我们收到该事件时,我们将再次使用Reponse.Write来跟踪执行流程。

一句警告:如果在任何时候事件神秘地停止工作,请检查InitializeComponent方法以确保设计者没有删除任何添加事件处理程序的代码。

答案 1 :(得分:2)

1)在用户控件中声明一个Public事件

2)在用户控件

内发布适当的RaiseEvent

3)在父页面的Init事件中,使用AddHandler将control.event分配给您要使用的处理过程

这很简单!

答案 2 :(得分:0)

我在@lordscarlet在他接受的解决方案中找到了与OdeToCode相同的解决方案。问题是我需要一个VB而不是C#的解决方案。它并没有完美地翻译。具体来说,在OnBubbleClick中检查事件处理程序是否为null并不能在VB中工作,因为编译器认为我试图调用该事件,并且发出一个错误,表示&#34; ...无法直接调用。使用&#39; RaiseEvent&#39;发表活动的声明。&#34;因此,这是使用名为CountryDropDownList的控件的OdeToCode解决方案的VB转换。

对于初学者,让我们创建一个带有下拉列表的用户控件。

<%@ Control Language="vb" AutoEventWireup="false" CodeBehind="CountryDropDownList.ascx.vb" Inherits="CountryDropDownList" %>
<asp:DropDownList runat="server" ID="ddlCountryList" OnSelectedIndexChanged="ddlCountryList_SelectedIndexChanged" AutoPostBack="true">
    <asp:ListItem Value=""></asp:ListItem>
    <asp:ListItem value="US">United States</asp:ListItem>
    <asp:ListItem value="AF">Afghanistan</asp:ListItem>
    <asp:ListItem value="AL">Albania</asp:ListItem>
</asp:DropDownList>

用户控件的代码如下所示。

Public Class CountryDropDownList
    Inherits System.Web.UI.UserControl
    Public Event SelectedCountryChanged As EventHandler

    Protected Sub ddlCountryList_SelectedIndexChanged(sender As Object, e As EventArgs)
        ' bubble the event up to the parent
        RaiseEvent SelectedCountryChanged(Me, e)
    End Sub
End Class

ASPX页面现在可以使用户控件正常工作。

<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="UpdateProfile.aspx.vb" Inherits="UpdateProfile" MaintainScrollPositionOnPostback="true" %>
<%@ Register Src="~/UserControls/CountryDropDownList.ascx" TagPrefix="SO" TagName="ucCountryDropDownList" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
    <HEAD>
        <title>WebForm1</title>
    </HEAD>
    <body>
        <form id="Form1" method="post" runat="server">
            <SO:ucCountryDropDownList id="ddlCountry" runat="server" />
        </form>
    </body>
</HTML>

在页面背后的代码中:

Protected Sub OnSelectedCountryChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles ddlCountry.SelectedCountryChanged
    ' add your code here
End Sub