【问题标题】:"Re-Raising" Custom Events in .NET (ASP.NET in this case)在 .NET 中“重新引发”自定义事件(在本例中为 ASP.NET)
【发布时间】:2008-12-02 15:27:56
【问题描述】:

我正在使用 VB.NET 处理 ASP.NET 页面,并且我有这个层次结构:

页面 A
- 网络用户控制 1
- 网络用户控制 A
- 网络用户控制 B
- 网络用户控制 C

我需要从 Web 用户控件 B 引发页面 A 将接收的事件(事件流将是 Web 用户控件 B -> Web 用户控件 1 -> 页面 A)。

到目前为止,我唯一的方法是: 1) 向 Web 用户控件 B 和 Web 用户控件 1 添加自定义事件声明,然后简单地 RaiseEvent 两次,直到它到达页面 A(这看起来很难看,我不是特别喜欢它)。

我的另一个想法是创建一个自定义 Event 类,该类继承自一些神奇的 Event 基类,并在 Web User Control B 和 Web User Control 1 中创建它的一个实例,但事实证明这是徒劳的,因为我找不到任何事件基类(也许它们不是任何事件基类,因为它似乎是关键字,而不是类名)。

任何帮助将不胜感激!谢谢,编码愉快!

【问题讨论】:

    标签: asp.net vb.net events


    【解决方案1】:

    您可以使用BubbleEvent concept 来执行此操作。一个 BubbleEvent 沿着控制层次上升,直到有人处理它。 GridView 和Repeater 控件通过它们的Row/ItemCommand 事件来执行此操作。

    您可以在 WebUserControl1 中实现它,将其变成页面的标准事件(就像 GridView 一样):

    Class UserControl1 ' Parent
       Protected Override Function OnBubbleEvent(sender as Object, e as EventArgs) as Boolean
           Dim c as CommandEventArgs = TryCast(e, CommandEventArgs)
           If c IsNot Nothing Then
               RaiseEvent ItemEvent(sender, c)
               Return True ' Cancel the bubbling, so it doesn't go up any further in the hierarchy
           End If
           Return False ' Couldn't handle, so let it bubble
       End Function
    
       Public Event ItemEvent as EventHandler(Of CommandEventArgs)
    End Class
    
    Class UserControlB ' Child
        Protected Sub OnClicked(e as EventArgs)
            ' Raise a direct event for any handlers attached directly
            RaiseEvent Clicked(Me, e)
            ' And raise a bubble event for parent control
            RaiseBubbleEvent(Me, New CommandEventArgs("Clicked", Nothing))
        End Sub
    
        Protected Sub OnMoved(e as EventArgs)
            ' Raise a direct event for any handlers attached directly
            RaiseEvent Moved(Me, e)
            ' And raise a bubble event for parent control
            RaiseBubbleEvent(Me, New CommandEventArgs("Moved", Nothing))
        End Sub
    End Class
    
    Class PageA
        Sub UserControl1_ItemEvent(sender as Object, e as CommandEventArgs) Handles UserControl1.ItemEvent
            Response.Write(sender.GetType().Name & " was " & e.CommandName)
        End Sub
    End Class
    

    或者,直接在页面中进行。 UserControlB(Child)同上,UserControl1(Parent)不需要做任何特别的事情——OnBubbleEvent默认返回False,所以事件冒泡了:

    Class PageA
       Protected Override Function OnBubbleEvent(sender as Object, e as EventArgs) as Boolean
           If sender Is UserControlB Then
               Dim c as CommandEventArgs = TryCast(e, CommandEventArgs)
               If c IsNot Nothing Then
                   Response.Write(sender.GetType().Name & " was " & c.CommandName)
               Else
                   Response.Write(sender.GetType().Name & " raised an event, with " & e.GetType().Name & " args)
               End If
               Return True ' Cancel the bubbling, so it doesn't go up any further in the hierarchy
           End If
           Return False ' Not handled
       End Function
    End Class
    

    如果您的初始事件来自服务器控件(如 Button.Click),那么它将已被编码为已经引发气泡事件 - 因此 UserControlB(Child)不需要做任何事情来获得它父母。您只需为任何自定义事件调用 RaiseBubbleEvent,或者如果您想以某种方式转换 EventArgs。

    【讨论】:

    • 这正是我想弄清楚的。完美答案!非常感谢(其他人也回答得很好)。
    【解决方案2】:

    这里真正的问题是 Web UserControl B 中的实际操作应该通知两者,或者,WebUserControl1 是否在通知页面之前负责一些处理。

    如果链条的每一步都有特定的动作,那么你提出两个事件的方法是正确的。如果是以事件只需要通知所有人的方式,您将希望查看不同的订阅方法进行通信。

    【讨论】:

      【解决方案3】:

      创建一个被所有东西引用的程序集(或命名空间)。 使用您需要的方法创建一个接口。 创建一个管理实现接口的对象的类。

      让页面 A 实现接口 让页面 A 在步骤 #3 中向管理器类注册自身 现在 Web UserControl B 可以通过从管理器中检索页面并在引发您需要的事件的接口上调用方法来引发事件。

      您避免将页面与 web 控件紧密耦合,因为您使用的是接口。

      您可能会发现您的项目的不同区域会有多个界面。例如,在我的 CAM 项目中,我有一个用于设置参数 UI、形状输入 UI 和剪切输入 UI 的界面。在我们的网站上,我们有使用不同界面的不同产品类别。 (软件、机械、服务等)。

      【讨论】:

        【解决方案4】:

        您可以在Page A 中创建一个从Web User Control B 调用的公共方法,而不是在整个控件树中引发事件。

        这不是我的第一选择,因为这会导致这些类之间的紧密耦合,但我希望它可以解决您的问题。

        示例页面:

        Public Partial Class TestPage
            Inherits Page
        
            Public Sub PerformAction()
                'Whatever needs to be done on Page A
            End Sub
        End Class
        

        用户控制示例:

        Public Partial Class TestControl
            Inherits UserControl
        
            Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
                'This will call the Page, obviously this will only
                'work when the control is on TestPage
                CType(Page, TestPage).PerformAction()
            End Sub
        End Class
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-03-25
          • 1970-01-01
          • 2011-02-27
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多