Declarative event handling from ASP.NET user control to page - asp.net

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.

Related

ASPX Webform - Programmatically created linkbutton never trigger event in UpdatePanel

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

Process Bar With Process Completion Messages

I am Executing Multiple store procedures on Button click event of my .aspx page
On each Procedure Execution i have to show a message on Process baar that
process 1 is completed.
process 2 is completed.
process 3 is completed.
please help in this
One way is to use an Update Panel in conjunction with Ajax Timer.
The following article may be useful.
http://msdn.microsoft.com/en-in/library/cc295400.aspx
The example given in the article shows you how to update a label in the Update Panel with current server time on the timer event. You can easily adapt the code to your needs and show whatever message you want to show instead of server time.
EDIT
As requested here is some sample code.
Add a new aspx file to your application and name it Test2.aspx
Replace the contents of aspx file as given below.
Run the application and see the sample code working.
Customize the DoWorkAsync method to suit your needs.
Run application and test your modified code.
The ASPX file:
<%# Page Language="VB" AutoEventWireup="false" CodeFile="Test2.aspx.vb" Inherits="Test2" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html dir="ltr" xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Asynchronous Update Demo</title>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager runat="server" ID="ScriptManager1">
</asp:ScriptManager>
<asp:UpdatePanel runat="server" ID="UpdatePanel1">
<ContentTemplate>
<asp:Timer runat="server" ID="Timer1" Interval="1000" />
<asp:Button ID="Button1" runat="server" Text="Start" /><br />
<asp:Label runat="server" Text="Click Start button to being processing." ID="Label1" />
</ContentTemplate>
</asp:UpdatePanel>
</form>
</body>
</html>
Code behind file:
(pay attention to inline comments)
Partial Class Test2
Inherits System.Web.UI.Page
Private MyAsyncProcessor As AsyncProcessor
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Session("MyAsyncProcessor") IsNot Nothing Then
' we are still processing.. so extract the reference of our class back from session variable
Me.MyAsyncProcessor = Session("MyAsyncProcessor")
End If
End Sub
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
' this event is fired everytime a timer ticks.
If MyAsyncProcessor IsNot Nothing Then
Label1.Text = MyAsyncProcessor.StatusMessage
If Not MyAsyncProcessor.IsProcessing Then
MyAsyncProcessor = Nothing
Session.Remove("MyAsyncProcessor")
Timer1.Enabled = False
End If
End If
End Sub
Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
Label1.Text = ""
Button1.Enabled = False
Timer1.Enabled = True
MyAsyncProcessor = New AsyncProcessor
MyAsyncProcessor.Start()
Session("MyAsyncProcessor") = MyAsyncProcessor 'save reference in a session variable
End Sub
End Class
Public Class AsyncProcessor
Public IsProcessing As Boolean
Public StatusMessage As String
Public Sub Start()
Dim th As New Threading.Thread(AddressOf DoWorkAsync)
th.Start()
End Sub
Private Sub DoWorkAsync()
' *** Replace this code with whatever work you want to do ***
' Set IsProcessing=True at beginnning of task and set it to False when exitting.
' Update the StatusMessage at regular intervals.
IsProcessing = True
For i = 1 To 10
'' this sleep is only to simulate a long going task
Threading.Thread.Sleep(1000)
StatusMessage &= String.Format("Task #{0} completed... <br>", i)
Next
StatusMessage &= "All tasks completed."
IsProcessing = False
End Sub
End Class
Another way is to delegate the work to a page in an iframe. On the iframe page, as your code is processed, you can update a Session variable to contain 'Finished Processing first step' (or whatever) and use PageMethods on the parent page to call a Web Method that gets the value of the session being updated by the code on the page in the iframe.

Calendar Controls, Event Handler for Load Event

I have been working on this for quite a while now. My code will show all the different ways and things that I have tried to get the problem fixed, but with no luck...so far. What I need to do is:
Start an event handler for the Load event of the form. Then add code to display the current date in the format shown above if the form is not being posted back.
Add a calendar control to the next paragraph, and set its Visible property to False so it's hidden when the form is first displayed.
Code an event handler for the Click event of the image button. This shold hide the image button and display the calendar control.
Code an event handler for the SelectionChanged event of the calendar control. This should get the selected date and display it in the text box with today's date and should also hide the calendar control and display the image button.
I hope that someone can help me sort out what I am doing wrong and help me get to the correct solution. Not really happy with the outcome so far.
My code-behind:
Partial Class Request
Inherits Page
Dim ImageButton1 As ImageButton1
Protected Sub Calendar_SelectionChanged(object sender, EventArgs e)
Label.Text = "Current date: " + System.DateTime.Now.ToLongDateString()
Label.Text = "Selected date: " + Calendar.SelectedDate.ToLongDateString()
Dim label1 = System.DateTime.Now
Dim label2 = SelectedDate
Dim ImageButton1 = ImageButton1
End Sub
protected void Calendar_SelectionChanged(object sender, EventArgs e)
{
lblday.Text = Calendar1.TodaysDate.ToShortDateString();
lblbday.Text = Calendar1.SelectedDate.ToShortDateString();
}
' Display using current (en-us) culture's short date format
Dim ddlDate As Date = #3/15/2008#
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
Calendar.SelectedDate = DateTime.Now;
Label.Text = "Today's date and time is :" + Calendar.SelectedDate;
Calendar.SelectedDate = DateTime.Today
End Sub
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
If Not IsPostBack Then
Me.clnArrival = thisDate.ToString
End If
End Sub
Sub Submit(s As Object, e As EventArgs)
TextBox1.Text = "The date and time is " & Now()
End Sub
Protected Sub ddlDay_SelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs) Handles ddlDay.SelectedIndexChanged
clnArrival.Visible = False
Dim day As String = ddlDay.SelectedItem.Text(ddlDay.SelectedValue)
End Sub
Protected Sub ddlMonth_SelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs) Handles ddlMonth.SelectedIndexChanged
Dim month As String = ddlMonth.SelectedItem.Text(ddlMonth.SelectedValue)
End Sub
Protected Sub clnArrival_SelectionChanged(ByVal sender As Object, ByVal e As EventArgs) Handles clnArrival.SelectionChanged
ddlMonth_SelectedValue = clnArrival.SelectedDate.Month.ToString
ddlDay_SelectedValue = clnArrival.SelectedDate.Day.ToString
clnArrival.Visible = True
End Sub
End Class
My markup:
<%# Page Language="VB" AutoEventWireup="false" CodeFile="Request.aspx.vb" Inherits="Request" %>
<!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>Chapter 6: Reservations</title>
<link href="Styles/Main.css" rel="stylesheet" type="text/css" />
<link href="Styles/Request.css" rel="stylesheet" type="text/css" />
<script language="VB" runat="server">
Sub Page_Load()
Response.Write("Today is: ")
End Sub
</script>
</head>
<body>
<form id="form1" runat="server">
<div id="page">
<h1>Royal Inn and Suites</h1>
<h2>Where you’re always treated like royalty</h2>
<p id="arrival_date">
Arrival date:
<asp:Calendar ID = "Calendar" runat = "server" SelectionMode="DayWeekMonth" OnSelectionChanged="Calendar_SelectionChanged" SelectedDate="1/1/0001" VisibleDate="1/1/0001">
<asp:ImageButton ID="ImageButton1" runat="server" AlternateText="Click to show calendar" ImageUrl="C:\aspnet4_vb\Jeanne Tatro Webs 424 - HW 6 - Ch06Reservation\Images\Calendar.bmp" />
</asp:Calendar>
</p>
<p class="clear">
Number of nights:
</p>
<p>
Number of adults:
Children:
</p>
<h3>Preferences</h3>
<p>
Room type:
</p>
<p>
Bed type:
</p>
<p id="requests">Special requests:</p>
<h3 class="clear">Contact information</h3>
<p class="contact">Name:</p>
<p class="contact">Email:</p>
<p id="buttons"></p>
<p id="message"></p>
</div>
</form>
</body>
</html>

Bind Property of ASP.NET User Control to One of the Parent Control's Fields

If I need access to the value of a user control's property BEFORE PreRender, would I need to base the custom control off of one of the preexisting data controls (repeater, listview, etc.)?
One of my user controls features a gridview control that is configured based on the user control's properties on which it resides. Several of the key properties alter the SQL Statement for the underlying recordsource. I'm now in a situation where the property that sets the WHERE statement for the SQL Statement needs to tied to a value in the user control's parent FormView. Think of the formview as displaying a customer detail record. The user control takes the customer's account number and then displays data from a related table such as Customer Contact Names. Since the gridview is created before the control's prerender event, working within the prerender event doesn't seem efficient.
See this question as a reference:
Stumped With Custom Property on User Control
What I said that you can assign value to the parent control when user control binds.
TestIt.ascx - Markup
<%# Control Language="VB" AutoEventWireup="false"
CodeFile="TestIt.ascx.vb" Inherits="usercontrols_TestIt" %>
<asp:Label
ID="lblOne"
runat="server">
</asp:Label>
TestIt.ascx.vb
Partial Class usercontrols_TestIt
Inherits System.Web.UI.UserControl
Public Property No As Integer
Get
Dim mno As Integer = 0
Integer.TryParse(lblOne.Text, mno)
Return mno
End Get
Set(value As Integer)
lblOne.Text = value.ToString()
End Set
End Property
Public ReadOnly Property Square As Integer
Get
Return No * No
End Get
End Property
Protected Sub Page_PreRender(sender As Object, e As System.EventArgs) Handles Me.PreRender
'Get ref. of parent control
Dim row As FormViewRow = CType(Parent.Parent, FormViewRow)
'Find control in parent control
Dim sqLabel As Label = row.FindControl("Label2")
'Assign value
sqLabel.Text = Square.ToString()
End Sub
End Class
ASPX - Markup
<%# Page Language="VB" AutoEventWireup="false" CodeFile="VbDefault2.aspx.vb" Inherits="usercontrols_VbDefault2" %>
<%# Register src="TestIt.ascx" tagname="TestIt" tagprefix="uc1" %>
<!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></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:FormView ID="FormView1" runat="server" AllowPaging="True">
<ItemTemplate>
No :
<uc1:TestIt ID="TestIt1" runat="server" No='<%#Eval("No") %>'
ClientIDMode="AutoID" />
<br />
Square :
<asp:Label ID="Label2" runat="server" ></asp:Label>
</ItemTemplate>
</asp:FormView>
</div>
</form>
</body>
</html>
ASPX.vb
Partial Class usercontrols_VbDefault2
Inherits System.Web.UI.Page
Public Class TestData
Public Property No As Integer
End Class
Protected Sub Page_Load(sender As Object, e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
BindData()
End If
End Sub
Sub BindData()
Dim nos As New List(Of TestData)
nos.Add(New TestData() With {.No = 10})
nos.Add(New TestData() With {.No = 20})
FormView1.DataSource = nos
FormView1.DataBind()
End Sub
Protected Sub FormView1_PageIndexChanging(sender As Object, e As System.Web.UI.WebControls.FormViewPageEventArgs) Handles FormView1.PageIndexChanging
FormView1.PageIndex = e.NewPageIndex
BindData()
End Sub
End Class

How do I apply AddHandler using OnCommand in ASP.NET

I've been racking my brain trying to get this to work. My event for my LinkButton isn't firing. I'm figuring that it has SOMETHING to do with ViewState and that the button is not there when it tries to fire the event after the Postback or something.
When I click the Add button,it adds the link to the page and then when I click the Diplay Time" linkbutton it should fire the event and display the CommandArgument data but it's not and i can't figure out why.
Here's my code:
<%# Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
End Sub
Protected Sub btnDelete_OnCommand(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.CommandEventArgs)
Response.Write(e.CommandArgument)
End Sub
Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs)
Dim btn As New LinkButton()
btn.ID = "lbn"
btn.Text = "Display Time"
btn.ValidationGroup = "vgDeleteSigner"
AddHandler btn.Command, AddressOf btnDelete_OnCommand
btn.CommandArgument = Now.TimeOfDay.ToString()
btn.EnableViewState = True
Panel1.Controls.Add(btn)
End Sub
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" />
<asp:Panel ID="Panel1" runat="server">
</asp:Panel>
</div>
</form>
</body>
</html>
The reason that's happening is that your dynamic button "lbn" needs to be drawn again on post back when it's clicked because the button doesn't exist after you click it.
Basically you just have to dynamically add the button to the page again on post back of click of that button.
I would recommend having the button already on the page but visible = false and then just showing it when you click the other button.

Resources