ASP .NET Web 用户控制事件
我创建了一个名为 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
你几乎已经回答了你自己的问题。为了在页面生命周期期间触发事件,服务器需要能够一致地重新创建客户端每次可用的所有控件。这是因为需要先创建原始控件,然后服务器才能在顶部加载其视图状态,然后识别客户端发生的更改。一旦确定了更改,服务器就会将更改映射到适当的事件并根据需要触发它们。
听起来您的控件并未在每个页面渲染上一致地创建,因此事件正在丢失,因为它无法附加到原始控件。
您可能想要尝试的一件事是将 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.