Динамическое событие командной кнопки ASP.NET не запускается
Я пытаюсь создать командные кнопки динамически, но нажатие соответствующей кнопки не вызывает соответствующее событие CommandButton_Click. Я заметил, что в примерах для SO установлено свойство Button.OnCommand, а также CommandName и CommandArgument, но это не вариант в intellisense.
Таким образом, вопрос в том, что я делаю не так (код ниже без OnCommand), доступ к нему осуществляется каким-либо другим способом - если так, то почему все найденные примеры показывают его как.OnCommand?
РЕДАКТИРОВАТЬ: Чтобы помочь, я добавил обработчик, однако событие все еще не запускается. Кнопки находятся в UpdatePanel и перестраиваются при каждой обратной передаче (вместе с обработчиком). Я создал упрощенный пример того, что я делаю, который показан ниже. Если срабатывает событие кнопки, он записывает "EVENT FIRED" в текстовое поле txtTestFired - достаточно сказать, что я никогда этого не видел. Это действительно сводит меня с ума, любая помощь очень благодарна.
файл.aspx
<form id="frmMain" runat="server">
<asp:ScriptManager ID="scmAddProducts" runat="server">
</asp:ScriptManager>
<asp:updatepanel runat="server">
<ContentTemplate>
<asp:TextBox ID="txtProduct" runat="server"></asp:TextBox>
<br />
<asp:Button ID="btnAddItem" runat="server" Text="Add Line" />
<asp:TextBox ID="txtTestFired" runat="server"></asp:TextBox>
<br />
<br />
<asp:Panel ID="pnlAddedLines" runat="server"></asp:Panel>
</ContentTemplate>
</asp:updatepanel>
</form>
файл.aspx.vb
Protected Sub btnAddItem_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnAddItem.Click
Dim dtItems As New System.Data.DataTable
If Session("Items") Is Nothing Then
Dim dcColumn As New System.Data.DataColumn
dcColumn.DataType = Type.GetType("System.String")
dcColumn.ColumnName = "Product"
dtItems.Columns.Add(dcColumn)
Session("Items") = dtItems
End If
dtItems = CType(Session("Items"), System.Data.DataTable)
Dim drRow As System.Data.DataRow
drRow = dtItems.NewRow()
drRow("Product") = txtProduct.Text
dtItems.Rows.Add(drRow)
Session("Items") = dtItems
txtProduct.Text = ""
End Sub
Protected Sub Page_PreRender(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreRender
If Not Session("Items") Is Nothing Then
Dim dtItems As System.Data.DataTable = CType(Session("Items"), System.Data.DataTable)
Dim iItemIndex As Integer = 1
For Each drRow In dtItems.Rows
Dim btnClose As New Button
btnClose.ID = "btnClose" & iItemIndex
btnClose.CssClass = "formCloseButton"
btnClose.Text = "X"
AddHandler btnClose.Click, AddressOf Button_Clicked
pnlAddedLines.Controls.Add(btnClose)
btnClose = Nothing
Dim txtProduct = New TextBox
txtProduct.ID = "txtProduct" & iItemIndex
txtProduct.CssClass = "formText"
txtProduct.Text = drRow("Product")
txtProduct.Columns = "40"
pnlAddedLines.Controls.Add(txtProduct)
iItemIndex += 1
Dim litHR = New Literal
litHR.Text = "<hr />"
pnlAddedLines.Controls.Add(litHR)
litHR = Nothing
Next
End If
End Sub
Private Sub Button_Clicked(ByVal sender As Object, ByVal e As System.EventArgs)
txtTestFired.Text = "EVENT FIRED"
End Sub
5 ответов
По сути, вам нужно создать исходные элементы управления один раз при загрузке страницы, чтобы иметь возможность обрабатывать нажатие кнопки, затем вам нужно очистить элементы управления и заново сгенерировать их либо в обработчике нажатия кнопки, либо как вы делали при предварительном рендеринге. - Я думаю, что он более понятен в обработчике кликов, поэтому вам нужен один и тот же код в обоих (предпочтительно рефакторинг в отдельный метод)
Пример ниже будет означать минимальные изменения кода для вас:
Protected Sub Page_PreRender(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreRender
If Not Session("Items") Is Nothing Then
pnlAddedLines.Controls.Clear()
GenerateControls()
End If
End Sub
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not Session("Items") Is Nothing Then
GenerateControls()
End If
End Sub
Private Sub GenerateControls()
Dim dtItems As System.Data.DataTable = CType(Session("Items"), System.Data.DataTable)
Dim iItemIndex As Integer = 1
For Each drRow In dtItems.Rows
Dim btnClose As New Button
btnClose.ID = "btnClose" & iItemIndex
Вы должны подключить его так (в C#):
myButton.Click += new EventHandler(this.Button_Clicked);
В качестве альтернативы вы можете ввести атрибут -> onclick = "Button_Clicked"
как это:
myButton.Attributes.Add("onclick", "Button_Clicked");
Если вы хотите это в VB.NET, перейдите на эту страницу и вырубите себя - я мог бы сделать это для вас, но какой в этом смысл:)
РЕДАКТИРОВАТЬ: имейте в виду, что вам придется повторно подключать обработчик событий (как показано выше) при каждой загрузке страницы.
РЕДАКТИРОВАТЬ: ОК. Теперь я вижу проблему, когда вы добавили остальную часть кода. Вы подключаете обработчик событий к pre_render. Обработчики событий выполняются непосредственно перед load_complete, что происходит до pre_render. Вот почему ваш event_handler не выполняется: вы добавляете его слишком поздно в жизненном цикле страницы. Поместите этот код в процедуру page_load, и она должна работать.
У меня была такая же проблема, я просто загружал элементы управления. события были запущены в первый раз, но не во второй раз. Проблема была в том, что у меня не было уникального идентификатора, привязанного к элементам управления. Поэтому я добавил уникальное поле идентификатора в элемент управления, который добавлял на страницу, и он работал просто отлично, каждый клик.
Правильный путь это:
- OnLoad - генерировать динамический контент (создавать динамические кнопки)
- Кнопка OnClick - использовать событие и восстановить правильный контент
Но для этого требуется сгенерировать контент дважды - один раз, чтобы кнопки "Создать" обрабатывали события, а затем стирали старый контент и генерировали правильный один-второй раз. Вы можете обойти это так:
- OnLoad - проверить, была ли нажата кнопка
- PreRender - генерировать правильный контент с помощью динамических кнопок (контент генерируется только один раз)
Мой пример для этого:
<script type="text/javascript" language="javascript">
function SetPostBackAction(Action,ReturnValue)
{
if(ReturnValue)
document.getElementById('<%=hfPostBackAction.ClientID%>').value=Action;
return ReturnValue;
}
</script>
<asp:HiddenField ID="hfPostBackAction" EnableViewState="false" runat="server" />
И в коде:
protected void Page_PreRender(object sender, EventArgs e)
{
//Dynamic button in PreRender
System.Web.UI.WebControls.Button btn=new System.Web.UI.WebControls.Button()
btn.ID=string.Format("DeleteButton_SomeData{0}", 12345);
btn.Text="Delete";
btn.OnClientClick=string.Format("return SetPostBackAction('DeleteButton_SomeData{0}',window.confirm('Are you sure to delete?'))", 12345);
btn.Click+=new EventHandler(btnDelete_Click);//This method will not be called if button is created in PreRender
}
protected void Page_Load(object sender, EventArgs e)
{
//Do something...
//Check Action
ProccessAction();//You can check action whereever you want
}
protected void ProccessAction()
{
string Action=Request.Form[hfPostBackAction.UniqueID]??string.Empty;
int SomeData;
if(Action.StartsWith("DeleteButton_"))//Is action?
{
SomeData=int.Parse(Action.Substring("DeleteButton_SomeData".Length));
//Do something...
}
//Erase Action field not to fire action next time accidentially
hfPostBackAction.Value=string.Empty;
}
Вам нужно подключить событие click. Смотрите этот код...
Partial Class _Default
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim button1 As New Button
Dim button2 As New Button
button1.ID = "button1"
button1.Text = "Button 1"
button2.ID = "button2"
button2.Text = "Button 2"
AddHandler button1.Click, AddressOf OnClick
AddHandler button2.Click, AddressOf OnClick
form1.Controls.Add(button1)
form1.Controls.Add(button2)
End Sub
Private Sub OnClick(ByVal sender As Object, ByVal e As System.EventArgs)
Dim buttonId As String
buttonId = DirectCast(sender, Button).ID
Response.Write("Button clicked: " + buttonId)
End Sub
End Class
Надеюсь это поможет...