ASP .NET Web 用户控制事件

发布于 2024-09-06 14:16:42 字数 2507 浏览 1 评论 0原文

我创建了一个名为 Activity 的 Web 用户控件。我在该 Web 用户控件上定义了一个名为 OnActivityDelete 的面向公众的事件。 Activity 控件中有一个删除按钮。单击删除按钮时,Activity 控件将触发 OnActivityDelete 事件。我正在中继器中使用此 Web 用户控件。我将事件处理程序分配给中继器的项目数据绑定事件上的 OnActivityDelete 事件。当我单击活动控件的删除按钮时,活动控件会触发事件,但它永远不会触发使用该控件的页面中的事件处理程序。 (我已使用调试器进入代码并确认了此行为)。

我怀疑这种行为与以下事实有关:当我将转发器绑定到数据源时,事件处理程序被添加到代码后面,而我仅在页面未回发时才执行此操作。

是否可以在 aspx 页面的标记中定义 Activity 控件的事件处理程序?如果是这样,这能解决我的问题吗?

如果没有,我是否必须绑定转发器并连接到每个页面加载的事件才能解决我的问题(这有效,我刚刚测试过),或者是否有一些视图状态技巧可以让事件持续存在?

页面上 Repeater 的标记:

<asp:Repeater ID="rptrActivites" runat="server" EnableViewState="true">
  <ItemTemplate>
    <div class="activity">
      <crm:Activity ID="activityView" runat="server" Activity="<%#Container.DataItem %>" EnableViewState="true" />
    </div>
  </ItemTemplate>
</asp:Repeater>

页面背后的代码:

  Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    If Not Page.IsPostBack Then
      GetActivities()
    End If

  End Sub

  Private Sub GetActivities()

    Dim oDS As DataSet

    'Code removed for brevity'

    rptrActivites.DataSource = oDataView
    rptrActivites.DataBind()

  End Sub

  Private Sub rptrActivites_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.RepeaterItemEventArgs) Handles rptrActivites.ItemDataBound

    If e.Item.ItemType = ListItemType.Item Or e.Item.ItemType = ListItemType.AlternatingItem Then
      Dim activityView As Activity = e.Item.FindControl("activityView")
      If activityView IsNot Nothing Then
        AddHandler activityView.OnActivityDelete, AddressOf ActivityDelete
      End If
    End If

  End Sub

  Private Sub ActivityDelete(ByVal sender As Object, ByVal e As ActivityDeleteEventArgs)
    'This never fires'
  End Sub

活动控件的标记:

<%@ Control Language="vb" AutoEventWireup="false" CodeBehind="Activity.ascx.vb" Inherits=".Activity" %>
<!-- code removed for brevity's sake -->
<asp:LinkButton ID="btnDelete" runat="server" Text="Delete" />
<!-- code removed for brevity's sake -->

活动控件背后的代码:

Public Event OnActivityDelete(ByVal sender As Object, ByVal e As ActivityDeleteEventArgs)

Private Sub btnDelete_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnDelete.Click
  RaiseEvent OnActivityDelete(Me, New ActivityDeleteEventArgs())
End Sub

I have created a web user control called Activity. I have defined a public-facing event on that web user control called OnActivityDelete. There is a delete button in the Activity control. When the delete button is clicked, the Activity control fires the OnActivityDelete event. I am using this web user control in a repeater. I assign an event handler to the OnActivityDelete event on the repeater's item data bound event. When I click the delete button for the Activity control, the event fires from the Activity control, but it never hits the event handler in the page that's using the control. (I have stepped into the code with the debugger and confirmed this behavior).

My suspicion is that this behavior has something to do with the fact that the event handlers are added in code behind when I bind the repeater to a datasource, which I only do if the page is not posting back.

Is it possible to define the event handler for the Activity control in the markup of the aspx page? If so, will this solve my problem?

If not, do I have to bind the repeater and hook up to the events every page load in order to solve my problem (this works, I just tested it), or is there some viewstate trick to getting the events to persist?

Markup of Repeater on page:

<asp:Repeater ID="rptrActivites" runat="server" EnableViewState="true">
  <ItemTemplate>
    <div class="activity">
      <crm:Activity ID="activityView" runat="server" Activity="<%#Container.DataItem %>" EnableViewState="true" />
    </div>
  </ItemTemplate>
</asp:Repeater>

Page's code behind:

  Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    If Not Page.IsPostBack Then
      GetActivities()
    End If

  End Sub

  Private Sub GetActivities()

    Dim oDS As DataSet

    'Code removed for brevity'

    rptrActivites.DataSource = oDataView
    rptrActivites.DataBind()

  End Sub

  Private Sub rptrActivites_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.RepeaterItemEventArgs) Handles rptrActivites.ItemDataBound

    If e.Item.ItemType = ListItemType.Item Or e.Item.ItemType = ListItemType.AlternatingItem Then
      Dim activityView As Activity = e.Item.FindControl("activityView")
      If activityView IsNot Nothing Then
        AddHandler activityView.OnActivityDelete, AddressOf ActivityDelete
      End If
    End If

  End Sub

  Private Sub ActivityDelete(ByVal sender As Object, ByVal e As ActivityDeleteEventArgs)
    'This never fires'
  End Sub

The markup of the Activity control:

<%@ Control Language="vb" AutoEventWireup="false" CodeBehind="Activity.ascx.vb" Inherits=".Activity" %>
<!-- code removed for brevity's sake -->
<asp:LinkButton ID="btnDelete" runat="server" Text="Delete" />
<!-- code removed for brevity's sake -->

Activity control code behind:

Public Event OnActivityDelete(ByVal sender As Object, ByVal e As ActivityDeleteEventArgs)

Private Sub btnDelete_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnDelete.Click
  RaiseEvent OnActivityDelete(Me, New ActivityDeleteEventArgs())
End Sub

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

分開簡單 2024-09-13 14:16:42

你几乎已经回答了你自己的问题。为了在页面生命周期期间触发事件,服务器需要能够一致地重新创建客户端每次可用的所有控件。这是因为需要先创建原始控件,然后服务器才能在顶部加载其视图状态,然后识别客户端发生的更改。一旦确定了更改,服务器就会将更改映射到适当的事件并根据需要触发它们。

听起来您的控件并未在每个页面渲染上一致地创建,因此事件正在丢失,因为它无法附加到原始控件。

您可能想要尝试的一件事是将 Repeaters 数据源放入视图状态/服务器属性中。这样,您只需昂贵地获取数据以在 !Page.IsPostBack 上绑定一次,然后就可以在每个页面加载时一致地重新绑定 Repeater。然后,这应该允许您的页面识别正在触发的事件的原始控制源,附加它,然后处理请求。

You've pretty much answered your own question. In order for an event to be fired during the page lifecycle the server needs to be able to consistently recreate all the controls that were available to the client each time. This is because the original controls need to be created before the server can load their viewstate on top and then identify the changes that occured on the client side. Once the changes have been identified the server will map the changes to the appropriate events and fire them as required.

It sounds like your controls are not being consistently created on every page render and therefore the event is being lost as it cannot be attached to the original control.

One thing you may want to try is placing your Repeaters datasource into a viewstate / server property. That way you only have to expensively fetch the data to bind once on !Page.IsPostBack and can then rebind the Repeater on every page load consistently. This should then allow your page to identify the original control source of the event being fired, attach it and then process the request.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文