ASPX Webform - Programmatically created linkbutton never trigger event in UpdatePanel - asp.net

I have a simple test app with a MasterPage, a Default.aspx page containing an UpdatePanel with few html and asp controls.
My purpose is to create dynamically controls and bind events.
I know the issue about IDs on controls and binding event handlers, as the the fact that you need to register an asynccontrol to the scriptmanager.
I tried many things but my dynamically created linkbutton goes in PostBack, in the MasterPage on_load but NEVER in my attached click event.
Extra infos : the declarative asp button triggers its click event after Default.aspx Page_Load and performing a Postback, the LinkButton dynamically created goes as well in the Default Page_Load but never trigger btnTest_Click2. This app is on .NET 4.5 (Visual Studio 2015).
Any idea ?
Thx.
Default.aspx :
<%# Page Title="Home Page" Language="VB" MasterPageFile="~/Site.Master" AutoEventWireup="false" CodeBehind="Default.aspx.vb" Inherits="TestUpdatePanel._Default" %>
<asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server">
<h1>This will never change !</h1>
<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:Button runat="server" ID="btnTest" CssClass="btn btn-success" OnClick="btnTest_Click" Text="Hit me hard !" />
<div runat="server" id="testDiv">
<p>Hello this a test</p>
</div>
</ContentTemplate>
<Triggers>
</Triggers>
</asp:UpdatePanel>
</asp:Content>
Default.aspx.vb code-behind :
Public Class _Default
Inherits Page
Dim currentsm As ScriptManager
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
currentsm = CType(Page.Master.FindControl("sm1"), ScriptManager)
If Not IsPostBack Then
MsgBox("It's not a postback", MsgBoxStyle.DefaultButton1)
Else
MsgBox("It's a Postback !", MsgBoxStyle.DefaultButton1)
End If
End Sub
Protected Sub btnTest_Click(sender As Object, e As EventArgs)
BuildButton()
End Sub
Private Sub BuildButton()
Dim link = New LinkButton
link.ID = "linkTest"
link.ClientIDMode = ClientIDMode.Static
link.Text = "This is a new Ajax link :-)"
AddHandler link.Click, AddressOf btnTest_Click2
Dim trigger As AsyncPostBackTrigger = New AsyncPostBackTrigger
trigger.ControlID = link.ClientID
trigger.EventName = "Click"
UpdatePanel1.Triggers.Add(trigger)
currentsm.RegisterAsyncPostBackControl(link)
testDiv.Controls.Add(link)
UpdatePanel1.Update()
End Sub
Private Sub BuildDiv()
Dim divToCreate = New HtmlGenericControl
divToCreate.TagName = "div"
divToCreate.ID = "newDiv"
divToCreate.ClientIDMode = ClientIDMode.Static
divToCreate.Attributes("class") = ("btn btn-alert")
divToCreate.InnerText = "It works !"
testDiv.Controls.Add(divToCreate)
UpdatePanel1.Update()
End Sub
Protected Sub btnTest_Click2(sender As Object, e As EventArgs)
BuildDiv()
End Sub

I finally got it with the use of the OnInit event to instanciate the dynamically created controls like this :
Protected Overrides Sub OnInit(e As EventArgs)
MyBase.OnInit(e)
If IsPostBack Then
currentsm = CType(Page.Master.FindControl("sm1"), ScriptManager)
Dim sender = Request.Form("__EVENTTARGET").ToString
If sender.Contains("btnTest") Then
BuildButton()
ElseIf sender.Contains("linkTest") Then
BuildDiv()
End If
End If
End Sub

Related

Find a control from an updatepanel and manipulate it

I have a .aspx page that contains a hidden panel that I need to display from a .ascx control.
On my .Click event from my button on my .ascx I have the following:
Dim myControl2 As Control = FindControl("Content1")
Dim myControl3 As Control = FindControl("keywordSearchModal")
On my .aspx I have the following:
<asp:Content ID="Content1" ContentPlaceHolderID="ContentHolder" runat="server">
<asp:Panel ID="keywordSearchModal" runat="server" Width="800px" Visible="true">
This is your modal
<asp:Button ID="OKButton" runat="server" Text="Close" />
</asp:Panel>
</asp:Content>
Both myControl2 and myControl3 contain nothing when the button is clicked.
How can I find this control from the .ascx that also happens to be an updatepanel.
UPDATE
I was able to find the control by doing the following:
Dim myPanel As Panel = Page.Master.FindControl("ContentHolder").FindControl("keywordSearchModal")
myPanel.Visible = False
Dim myControl As Control = Page.Master.FindControl("ContentHolder").FindControl("keywordSearchModal")
myControl.Visible = False
I was able to use the ContentPlaceHolderID - However now I can't change the visibility...
UPDATE II
thanks to the suggestion below I was able to capture the button click on my .aspx page. However, now just like before I can't seem to manipulate the control. In this example adding text to the panel.
Protected Sub SearchStart(ByVal sender As Object, ByVal e As EventArgs) Handles EquipmentDetails1.SearchStart
Dim newLabel As New Label
newLabel.Text = "This is a label!"
keywordSearchModal.Controls.Add(newLabel)
End Sub
Thoughts?
Here is what I've used in the past...
My user control has an imagebutton and the following in the codebehind
Public Event SearchStart As EventHandler
'This will be the event triggered when the imagebutton is clicked
Protected Sub ib_Search_Click(ByVal sender As Object, ByVal e As EventArgs) Handles ib_Search.Click
'Bubble up event to parent
RaiseEvent SearchStart(Me, e)
End Sub
Any page that uses the User Control will have the following in codebehind...
Protected Sub mc_SearchFilter_SearchStart(ByVal sender As Object, ByVal e As EventArgs) Handles mc_SearchFilter.SearchStart
'CODE that needs to be executed when search image button is clicked in my_control_SearchFilter
End Sub
Hope that helps....

Adding .net RadioButtonsList control dynamically in code file, no SelectedValue in Post Back

I am having trouble getting the SelectedValue from a RadionButtonsList that I'm creating dynmically in a code file. I'm adding it to a PlaceHolder control on the aspx page. After PostBack the radio button keeps its selection on the page, but I am not able to get the value from within the code file.
I understand I can create the RadioButtonsList in the HTML page, but I need to understand how to accomplish this from only the code file. The real problem I'm having is more complicated. (Creating dynamic number of true/false RadioButtonsList controls)
quiz.aspx
<%# Page Title="Quiz" MasterPageFile="~/MasterPage.master" Language="VB" CodeFile="quiz.aspx.vb" Inherits="quiz" %>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
<asp:PlaceHolder ID="testholder" runat="server"></asp:PlaceHolder>
<asp:Button ID="lblNext" runat="server" type="submit" Text="Next" accesskey="n"/>
</asp:Content>
MasterPage.master
<%# Master Language="VB" CodeFile="MasterPage.master.vb" Inherits="MasterPage" %>
quiz.aspx.vp
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim testlist As New RadioButtonList
testlist.Items.Add(New ListItem("test 1", "test1"))
testlist.Items.Add(New ListItem("test 2", "test2"))
testholder.Controls.Add(testlist)
If (IsPostBack) Then
Debug.WriteLine("testlist: " & testlist.SelectedValue)
End If
End Sub
My output after submit is: "testlist: ". Any ideas?
You have to load the controls before page_load event is triggered so that loadpostbackdata will get a chance to load the viewstate of the dynamic controls.
I am able to see the selected value after moving the dynamic controls to page_init event.
Dim testlist As New RadioButtonList
Protected Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs)
{
testlist.Items.Add(new ListItem("test1", "test1"))
testlist.Items.Add(new ListItem("test2", "test2"))
testholder.Controls.Add(testlist)
}
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
{
If (IsPostBack) Then
Debug.WriteLine(testlist.SelectedValue)
End If
}

Handling events of usercontrols within listview

I have a simple usercontrol which raises an event on button click
Public Class UcPaymentCheque
Inherits System.Web.UI.UserControl
Public Event OnCancelClick()
Private Sub btnCancelPayment_Click(sender As Object, e As System.EventArgs) Handles btnCancelPayment.Click
RaiseEvent OnCancelClick()
End Sub
End Class
This usercontrol is used within a listview
<asp:ListView ID="lvwNonTpProducts" runat="server" ItemPlaceholderID="ItemPlaceholder">
<LayoutTemplate>
<asp:PlaceHolder ID="ItemPlaceholder" runat="server" />
</LayoutTemplate>
<ItemTemplate>
<TPCustomControl:UcPaymentCheque ID="UcTPPaymentCheque" runat="server" Visible="false" />
</ItemTemplate>
</asp:ListView>
which is databound on page load
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Page.IsPostBack Then
Else
BuildPage()
End If
End Sub
At what point should add the handler? I have fiddled with the ondatabound event like so;
Private Sub lvwNonTpProducts_ItemDataBound(sender As Object, e As System.Web.UI.WebControls.ListViewItemEventArgs) Handles lvwNonTpProducts.ItemDataBound
Dim UcTPPaymentCheque = DirectCast(e.Item.FindControl("UcTPPaymentCheque"), UcPaymentCheque)
AddHandler UcTPPaymentCheque.OnCancelClick, AddressOf OnCancelClick
End Sub
but this does not work and am guess at a databound issue???
You can check out my response to a similar question here: creating and listening for events
Essentially, you want a user control to raise its own event, like this:
Partial Class myControl
Inherits System.Web.UI.UserControl
Public Event MyEvent As EventHandler
'your button click event
Protected Sub bnt_click(ByVal sender As Object, ByVal e As EventArgs)
'do stuff
'now raise the event
RaiseEvent MyEvent (Me, New EventArgs)
end sub
end class
In this example, I raise the event when the user clicks a button within the user control. You can easily raise the event anywhere, such as when the control loads, using a timer, whatever.
Then, in the main page, you want to and an event handler to the user control, like this:
<mc:myControlrunat="server" ID="myControl1" OnMyEvent="myControl_MyEvent" />
Now, in the code behind, you can add the event, like this:
Protected Sub myControl_MyEvent(ByVal sender As Object, ByVal e As EventArgs)
'do stuff
end sub
You can add the handler in the declaration of the user control in the listview, using OnCancelClick, as follows:
<asp:ListView ID="lvwNonTpProducts" runat="server" ItemPlaceholderID="ItemPlaceholder">
<LayoutTemplate>
<asp:PlaceHolder ID="ItemPlaceholder" runat="server" />
</LayoutTemplate>
<ItemTemplate>
<TPCustomControl:UcPaymentCheque ID="UcTPPaymentCheque" runat="server" Visible="false" OnCancelClick="UcTPPaymentCheque_OnCancelClick" />
</ItemTemplate>
</asp:ListView>
Where UcTPPaymentCheque_OnCancelClick is the function you should use to handle the event, in the control that contains the listview.

Addhandler, button.click not firing using VB.NET

I am experiencing a problem with buttons and AddHandler. It only works if I use AddHandler Button1.click, AddressOf... in Page_load, but if I create the button dynamically in one of the sub routines, the event doesn't fire.
For example,
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
<asp:DropDownList ID="DropDownList1" runat="server" AutoPostBack="True">
<asp:ListItem>1</asp:ListItem>
<asp:ListItem>2</asp:ListItem>
</asp:DropDownList>
<asp:ScriptManager id="ScriptManager1" runat="server"></asp:ScriptManager>
<asp:UpdatePanel id="UpdatePanel1" runat="server" UpdateMode="Conditional" ChildrenAsTriggers="False">
<contenttemplate>
<asp:PlaceHolder id="PlaceHolder1" runat="server"></asp:PlaceHolder>
</contenttemplate>
</asp:UpdatePanel>
<asp:UpdatePanel id="UpdatePanel2" runat="server" UpdateMode="Conditional">
<contenttemplate>
<asp:Label id="Label2" runat="server" Text="Label"></asp:Label>
</contenttemplate>
</asp:UpdatePanel>
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
Label1.Text = Date.Now
ScriptManager1.RegisterAsyncPostBackControl(DropDownList1)
End Sub
Protected Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs)
Label2.Text = "Panel refreshed at " + Date.Now.ToString()
End Sub
Protected Sub DropDownList1_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles DropDownList1.SelectedIndexChanged
Dim b As New Button
b.Text = "Click"
ScriptManager1.RegisterAsyncPostBackControl(b)
AddHandler b.Click, AddressOf Button1_Click
PlaceHolder1.Controls.Add(b)
UpdatePanel1.Update()
End Sub
The dropdownlist works, but the button doesn't. What am I doing wrong?
You have to regenerate your dynamically created controls on every postback (at last in Page_Load, better in Page_Init). You have to set the ID of the controls accordingly because ASP.Net needs it to identify which control caused a Postback and to handle the appropriate events.
You could save the number of created buttons in ViewState and use this to regenerate them on Page_Load. Increase the number when you add a new button. Use this number also to make the Button's ID unique(append it to the ID) to ensure that its the same on every postback.
For further informations, have a look the Page-Lifecycle and ViewState with dynamically added controls.
Edit: As Joel commented, if you only need one Button you can set it's ID statically, but you have to regenerate it on postback f.e. to handle its click-event.
Just to aid anyone who has this problem and isn't quite sure how to implement. Here's a quick example.
This example starts out by displaying a dropdownlist. When user selects something from the dropdown, another dropdownlist appears.
I typed this off the top of my head, so it MAY contain errors, but you get the idea =)
In the aspx file, add a placeholder:
And in your codebehind:
...
Protected Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Init
'Store control count in viewstate
If Not IsPostBack Then ViewState("ControlCounter") = 1
'Rebuild dynamic controls on every postback so when page's life cycle hits Page_Load,
'selected values in the viewstate (asp.net default behavior) can be loaded into the dropdowns
Build_Dynamic_Controls()
End Sub
Protected Sub Build_Dynamic_Controls()
'Clear placeholder
myPlaceholder.Controls.Clear()
'This is where the control counter stored in the viewstate comes into play
For i as Integer = 0 To CInt(ViewState("ControlCounter") -1
Dim ddlDynamic as New DropDownList With {
.ID = "ddlDynamicDropdown" & i,
.AutoPostBack = True
}
'This is the event that will be executed when the user changes a value on the form
'and the postback occurs
AddHandler ddlDynamic.SelectedIndexChanged, AddressOf ddlDynamic_SelectedIndexChanged
'Add control to the placeholder
myPlaceholder.Controls.Add(ddl)
'Put some values into the dropdown
ddlDynamic.Items.Add("Value1")
ddlDynamic.Items.Add("Value2")
ddlDynamic.Items.Add("Value3")
Next i
End Sub
Protected Sub ddlDynamic_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs)
'When a dropdown value is changed, a postback is triggered (autopostback=true)
'The event is captured here and we add another dropdown.
'First we up the control count:
ViewState("ControlCounter") = CInt(ViewState("ControlCounter")) + 1
'Now that the "total controls counter" is upped by one,
'Let's recreate the controls in the placeholder to include the new dropdown
Build_Dynamic_Controls()
End Sub
...

Declarative event handling from ASP.NET user control to page

I am trying to figure out how to declaratively pass in a event handler into
a user control, but I am stumped. All I can make work is the user control's
event handler.. I can't seem to bubble up the caught event into the parent
page. Ideas would be quite welcome. Here is my code:
Default.aspx:
<%# Page Language="VB" %>
<%# Register TagPrefix="rpt" TagName="filter" Src="WebUserControl.ascx" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Test Controls</title>
</head>
<body>
<form id="form1" runat="server">
<rpt:filter ID="DataView1Filters" runat="server" SelectedIndexChanged="DropDown_SelectedIndexChanged" />
<asp:Label ID="Label1" runat="server" />
</form>
<script runat="server">
Public Sub DropDown_SelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs)
Label1.Text = String.Format("Inside declarative event handler. {0}<br>", Label1.Text)
End Sub
</script>
</body>
</html>
WebUserControl.ascx:
<%# Control Language="VB" ClassName="WebUserControlTest" %>
<asp:Panel ID="TestPanel" runat="server"></asp:Panel>
<script runat="server">
Private AllEvents As New System.ComponentModel.EventHandlerList
Public Custom Event SelectedIndexChanged As EventHandler
AddHandler(ByVal value As EventHandler)
AllEvents.AddHandler("SelectedIndexChanged", value)
End AddHandler
RemoveHandler(ByVal value As EventHandler)
AllEvents.RemoveHandler("SelectedIndexChanged", value)
End RemoveHandler
RaiseEvent(ByVal sender As Object, ByVal e As System.EventArgs)
Dim value As EventHandler = CType(AllEvents("SelectedIndexChanged"), EventHandler)
If Not value Is Nothing Then
value.Invoke(sender, e)
End If
End RaiseEvent
End Event
Private Sub _SelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs)
Dim ctrl As DropDownList = Me.FindControl("TestDropDownList")
If Not ctrl Is Nothing Then
Me.ViewState("ItemSelection") = ctrl.SelectedIndex
End If
Dim Label1 As Label = Parent.FindControl("Label1")
Label1.Text = String.Format("Inside user control event handler. {0}<br>", Label1.Text)
RaiseEvent SelectedIndexChanged(sender, e)
End Sub
Private Overloads Sub OnLoad(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
Dim ctrl As New DropDownList
With ctrl
.ID = "TestDropDownList"
.Items.Clear()
.AutoPostBack = True
AddHandler .SelectedIndexChanged, AddressOf _SelectedIndexChanged
.Items.Add(New ListItem("-- Select --", String.Empty))
.Items.Add(New ListItem("Item 1", "1"))
.Items.Add(New ListItem("Item 2", "2"))
If Not Me.ViewState("ItemSelection") Is Nothing Then
.SelectedIndex = CInt(Me.ViewState("ItemSelection"))
Else
.SelectedIndex = 0
End If
End With
TestPanel.Controls.Add(ctrl)
End Sub
</script>
Thanks!
See this previous post:
Handling User Control Events on Containing Page
Edit - added based on your comment
I should have read the question more clearly.
As far as having a UserControl raise an event that the containing page can respond to, I do not believe that this can be done declaratively.
Unless my knowledge is just lacking, the only way to accomplish this is by explicitly creating an event in the control and then handling it (by coding the event handler) on the parent page, as shown in the example I linked to.
I was recently having this same issue in C#. When you set up an event called SelectedIndexChanged asp.net will bind the attribute OnSelectedIndexChanged when using the declarative syntax.
So if you change
<rpt:filter ID="DataView1Filters" runat="server" SelectedIndexChanged="DropDown_SelectedIndexChanged" />
To
<rpt:filter ID="DataView1Filters" runat="server" OnSelectedIndexChanged="DropDown_SelectedIndexChanged" />
It should work.

Resources