Event won't fire to dynamically added control - asp.net

I'm dynamically adding htmlvideo controls to my web form based on the number of videos present on the server folder. This part works fine. All the videos show up and can be played. I add the 'onended' event as an attribute and the function in my code behind, but this event won't fire. I'm aware that since these controls are added after the fact I have to add a listener, but just don't know how.
This is the code that adds the controls
Dim SavePath As String = "e:\ftproot\images\TechNet\"
Dim Directory As New DirectoryInfo(SavePath)
Dim allFiles As IO.FileInfo() = Directory.GetFiles("*.mov")
Dim VidCtr As Integer = 1
For Each singlefile In allFiles
Dim myVid As New HtmlVideo
myVid.Src = "https://www.rawauto.com/images/TechNet/" & singlefile.Name
myVid.Attributes.Add("height", 140)
myVid.Attributes.Add("runat", "server")
myVid.Attributes.Add("type", "video/mp4")
myVid.Attributes.Add("controls", "controls")
myVid.Attributes.Add("onended", "VidPlayed")
myVid.Attributes.Add("id", "Vid" & VidCtr)
Panel1.Controls.Add(myVid)
Dim myLbl As New Label
myLbl.Text = Replace(UCase(singlefile.Name), ".MOV", "")
myLbl.Width = 250
myLbl.CssClass = "VidStyle"
myLbl.Font.Name = "calabri"
myLbl.Font.Bold = True
LPanel.Controls.Add(myLbl)
Next
This is the function I'm trying to fire once the user has finished watching the video:
Protected Sub VidPlayed(sender As Object, e As EventArgs)
Dim Tech As New SqlConnection("server=RAW-OTT; Initial Catalog=TechNet; Integrated Security=True;")
Dim vid As HtmlVideo = sender
Dim vidurl As String = vid.Src
VidName = Replace(vidurl, "https://www.rawauto.com/images/TechNet/", "")
If Len(VidName) > 50 Then
VidName = Mid(VidName, 1, 50)
End If
Dim SqlStr As String = "Select * From TechTube Where Video = '" & VidName & "'"
Dim ttA As New SqlDataAdapter(SqlStr, Tech)
Dim ttT As New DataTable
ttA.Fill(ttT)
If ttT.Rows.Count = 0 Then
SqlStr = "Insert Into TechTube Values ('" & VidName & "', 1, 0)"
Dim tCmd As New SqlCommand(SqlStr, Tech)
Tech.Open()
tCmd.ExecuteNonQuery()
Tech.Close()
Else
SqlStr = "Update TechTube Set Hits = Hits + 1 Where Video = '" & VidName & "'"
Dim tCmd As New SqlCommand(SqlStr, Tech)
Tech.Open()
tCmd.ExecuteNonQuery()
Tech.Close()
End If
RateLabel.Visible = True
RatingBox.Visible = True
End Sub

This is an old ViewState problem for any dynamic control, and has nothing specific to do with video.
Remember, every PostBack rebuilds the entire page from scratch, including your dynamic controls. If you still want to see these controls after a postback (which includes all server events), you must re-add them to the page. Additionally, you need a control's ViewState restored if you want an event fired for the control during this PostBack, and for the ViewState to restore the control must be added back to the reconstructed page before the Page_Load event runs. Page_Init or Page_PreInit can work well for this.
Finally, consider the performance implications here. Do you really want to rebuild the entire page on every user interaction, or is it perhaps time to learn to use javascript to process these things, with maybe a web api that only has to receive a javascript request without causing an entire page cycle both on your server and in the user's browser?
Just a few of the many other times this has been asked and answered:
Dynamic Event Handler not Firing
dynamically added buttons not firing click event c#
dynamically created button click event not firing
Dynamically Added DropDownlists Are Not Firing SelectedIndexChanged Event
ASP.NET: Viewstate and programmatically adding user controls
Click events on Array of buttons
VB ASP dynamic button click event not hitting handler event

Related

VB ASP.NET - Add code to a control that is created by code behind

I'm using VB ASP.NET and would like to know how to add code to a control that is created by code behind?
For example in my Main.aspx.vb file I have the following code:
Connection.Open()
spRetrieveAlbums.ExecuteNonQuery()
ReturnValue = spRetrieveAlbums.Parameters("#ReturnValue").Value
Connection.Close()
For I = 1 To ReturnValue
Dim myAlbum = New ImageButton
myAlbum.Visible = True
myAlbum.Width = 150
myAlbum.Height = 150
myAlbum.BorderStyle = BorderStyle.Solid
myAlbum.BorderColor = Drawing.Color.WhiteSmoke
myAlbum.BorderWidth = 1
AlbumsPanel.Controls.Add(myAlbum)
Next I
ReturnValue stores the number of albums a person has (Using SQL Server stored procedure ##ROWCOUNT) and displays the same amount of ImageButtons within the 'AlbumsPanel' Panel on the web page.
I would like to use response.redirect("Albums.aspx") on a click event on any of the ImageButtons but not sure how I can achieve this. Any suggestions?
you have created dynamically and you can use a delegate for min.VB10 and like that,
AddHandler myAlbum.Click, _
Sub(sender As Object, e As EventArgs)
//To Do for Response
End Sub

value of variables not changing in asp.net

currently I am working on a project named online exam.
All the controls are dynamically created.
I have a webpage where I want to display the student details.
I displayed those details correctly in a table.
Now here comes the time to edit those details.
To edit a record I use the linked button named edit.
When a user clicks on that Linked button the data in that row is replaced with new textboxes.
Upto here I am OK.
Now when I click on the save changes button after making changes to the textboxes.
The old values are not replaced by the new values and the old values remains.
The code for creating textboxes in the table is as follows :
Public Sub Edit_Click(ByVal sender As Object, ByVal e As System.EventArgs)
For x As Integer = 0 To EditList.Count - 1
If sender.id.substring(4) = EditList(x).ID.Substring(4) Then
Session("PreviousRollNo") = RollNoList(x).Text
Dim txtName As New TextBox
txtName.Text = NameList(x).Text
NameList(x).Text = ""
NameList(x).Parent.Controls.Add(txtName)
txtList.Add(txtName)
Dim txtCourse As New TextBox
txtCourse.Text = CourseList(x).Text
CourseList(x).Text = ""
CourseList(x).Parent.Controls.Add(txtCourse)
txtList.Add(txtCourse)
Dim txtAdmissionDate As New TextBox
txtAdmissionDate.Text = AdmissionList(x).Text
AdmissionList(x).Text = ""
AdmissionList(x).Parent.Controls.Add(txtAdmissionDate)
txtList.Add(txtAdmissionDate)
Dim btnSaveChanges As New Button
btnSaveChanges.Text = "Save Changes"
EditList(x).Text = ""
EditList(x).Parent.Controls.Add(btnSaveChanges)
AddHandler btnSaveChanges.Click, AddressOf btnSaveChanges_Click
Session("EditButtonClicked") = True
Dim btnCancel As New Button
btnCancel.Text = "Cancel"
DeleteList(x).Text = ""
DeleteList(x).Parent.Controls.Add(btnCancel)
AddHandler btnCancel.Click, AddressOf btnCancel_Click
Session("CancelButtonClicked") = True
txtName.Focus()
Exit For
End If
Next
End Sub
The code for Save Changes button is as follows :
Public Sub btnSaveChanges_Click(ByVal sender As Object, ByVal e As System.EventArgs)
If txtList(0).Text = "" Then
Dim trError As TableRow = New TableRow
Dim tdError As TableCell = New TableCell
tdError.ColumnSpan = 7
Dim lblError As New Label
lblError.Text = "Please enter name of the student."
lblError.ForeColor = Drawing.Color.Red
tdError.Controls.Add(lblError)
trError.Controls.Add(tdError)
tbl.Controls.Add(trError)
ElseIf txtList(1).Text = "" Then
Dim trError As TableRow = New TableRow
Dim tdError As TableCell = New TableCell
tdError.ColumnSpan = 7
Dim lblError As New Label
lblError.Text = "Please enter the course."
lblError.ForeColor = Drawing.Color.Red
tdError.Controls.Add(lblError)
trError.Controls.Add(tdError)
tbl.Controls.Add(trError)
ElseIf txtList(2).Text = "" Then
Dim trError As TableRow = New TableRow
Dim tdError As TableCell = New TableCell
tdError.ColumnSpan = 7
Dim lblError As New Label
lblError.Text = "Please enter the Admission Date"
lblError.ForeColor = Drawing.Color.Red
tdError.Controls.Add(lblError)
trError.Controls.Add(tdError)
tbl.Controls.Add(trError)
Else
Dim cb As New OleDbCommandBuilder(da)
Dim editRow() As DataRow
editRow = ds.Tables("Student_Detail").Select("Roll_No = '" & Session("PreviousRollNo") & "'")
editRow(0)("Name") = txtList(0).Text
editRow(0)("Course") = txtList(1).Text
editRow(0)("Admission_Date") = txtList(2).Text
da.Update(ds, "Student_Detail")
Page.Response.Redirect("ChangeUserDetails.aspx")
End If
End Sub
I get the error sying that array is out of the bounds. on the first line of the btnSaveChanges_Click.
It means txtlist is always cleared when I click on Save Changes Button.
So I stored txtList in a Session like Session("txtList") = txtList.
and retrieved the data from that. But now I get the old values of the textbox instead of the newer ones.
Here txtList is a list (of Textbox)
Firstly, welcome to the ASP.NET WebForms Page Life Cycle. Remember its pattern with the simple mnemonic: SILVER = Start, Init, Load, Validate, Events, Render.
Secondly, HTTP is stateless. WebForms does an amazing job of hiding this fact from you using ViewState until you do something a little out of the ordinary (as you're now attempting), and it all appears to fall apart. What's really happening is that you're starting to see side-effects of how WebForms is managed, and how it's not as much like WinForms (or another stateful system) as you might think.
When you're responding to an event server-side in WebForms, it's easy to get the impression that nothing has changed. That the entire page is as you left it "last time". All the controls are there, the values you may have set programatically are still set. Magic. Not magic. What's actually happened is the entire page has been re-constructed to respond to that event. How was it re-constructed? By a combination of your page definition (markup), actions taken in control event handlers, and the form data posted back by the client.
Confusing? OK, let's consider an example. Say you've got a page with two controls on it. A textbox named txtInput and a button named btnSubmit with event handler btnSubmit_Click. When the user first requests the page, the HTML for these controls is derived from your markup (aspx page) and returned to the client. Next, the user sets a value in txtInput and clicks the submit button. The server then re-creates the page from scratch based on your markup. At this early stage of the life-cycle, the controls still have their default values. We then hit the Load stage of the life-cycle, and "if the current request is a postback, control properties are loaded with information recovered from view state and control state." In other words, by the time the life-cycle gets to Init, the control has been created from markup, but still has its default value. The Load stage then sets the value according to Postback data.
Left wondering how this applies to your scenario? You're adding your dynamic controls in response to a control event. There's two things wrong with that:
It's too late in the page life-cycle for Init to set the values based on data posted back from the client (recall SILVER, Event is after Init).
Your button click event handler is only run once, in response to the postback where the user clicked the button. But remember on each postback the page is entirely re-created. So the dynamic controls no longer exist as far as the server is concerned! You'll notice that not only are the controls not present server side when responding to the submit event, but after the page has handled it, they're no longer present client-side either.
So what's the answer? Well the "Life-Cycle Events" section of the page I linked offers a clue. It states that the PreInit event be used to (among other things) "Create or re-create dynamic controls". Why would we do it in PreInit? So it's early enough in the page life-cycle for the later events to properly handle it (like setting the values posted back from the client).
Now, I know, you want to add the controls based on the user clicking on the button. How does that fit? The trick is that you've got to manage the "state" yourself. Huh? the state? By this I mean MyDynamicControlsShouldBeShown = true / false. When the button is clicked, creating the controls in response to the button-click event handler is the right action (there's not really any choice there). But you need to store that state somehow so you know on subsequent requests to the page, whether those controls should be re-created in PreInit. One neat option would be to check for the ID of your dynamic control in Request.Form.Keys. If the control ID is present in the Keys collection, then the user is posting back a value for the control, so you should re-create it.
A side-note on the use of Session
Hopefully based on the above you've realised why putting the controls into Session didn't work. But to be clear, the controls you put into the Session object were no longer part of a page that existed (remember, the page gets completely re-created for each request. Those controls were no longer hooked up to the Page events, so didn't get their values populated between Page Init and Load. If somehow it did work, it still wouldn't be a particularly good idea, as Session is not per-request. So what would happen if a user had the same page open in multiple tabs? Strange things, that's what.

Checkbox list keep disabled

Trying to use checkbox lists in (calendar booking system). The checkbox should be disabled and red if there are any data in the database against the date and hour. This all work perfectly here is the code. Using vb.net
OK i found a way how to clear the checkboxes
Dim i As Integer
Dim chboxItem As ListItem
For Each chboxItem In CheckBoxListMon.Items
i += 1
If (i Mod 1 = 0) Then
chboxItem.Enabled = True
End If
Next
Protected Sub Page_LoadComplete(sender As Object, e As EventArgs) Handles Me.LoadComplete
Try
strQuery = "SELECT BookingDate, checkBoxItem, BookRegUserID,Booked FROM bookings INNER JOIN checkboxitems where checkBoxItem = BookingTime"
MySQLCmd = New MySqlCommand(strQuery, dbCon)
dbCon.Open()
DR = MySQLCmd.ExecuteReader
While DR.Read
bookDate = DR.Item("BookingDate")
bookTime = DR.Item("checkBoxItem")
bookRegID = DR.Item("BookRegUserID")
booked = DR.Item("Booked")
Dim test As String = bookTime.ToString()
Select Case True
Case bookDate = lblMonday.Text And CheckBoxListMon.Items.FindByValue(test) IsNot Nothing
CheckBoxListMon.Items.FindByValue(bookTime).Enabled = False
CheckBoxListMon.Items.FindByValue(bookTime).Attributes.Add("Style", "color: red;")
End Select
End While
DR.Close()
dbCon.Close()
Catch ex As Exception
End Try
End Sub
When the page load it would not change the ones from the database. But when i reload the page it will actually work perfect.
Where can i put the check just to be sure that they are already in the memory.
Any help will be much appreciated. Thanks all.
Petr
You need to refresh the data when another week is selected because you are using the same controls for each week. You should be able to do this in whatever control you are using to toggle through the weeks.
Page_LoadComplete can only be expedted to fire each time a page has completed loading, that is why your controls work when going to another page and back.

Can't clear credentials textboxes on ASP.NET CreateUserWizard Control

I have a CreateUserWizard control using forms authentication on my login/create user page. I customized the CreateUserWizardStep1 so that I could add some additional validators.
After successfully creating a user with the control and it displays "Complete
Your account has been successfully created." I have added an additional button that will allow the person to create another user by setting the ActiveStepIndex = 0. The problem is, while it sets the ActiveStepIndex correctly, it retains the old user account credentials. I try to clear them manually using the following code, but they still stick...Anyone have any ideas?
Protected Sub btnCreateAnotherUser_Click(ByVal sender As Object, ByVal e As System.EventArgs)
Me.cuwMain.ActiveStepIndex = 0
CleanCreateNewUserInput()
End Sub
Private Sub CleanCreateNewUserInput()
Dim txtUserName As TextBox
txtUserName = FindControlIterative(Me.cuwMain, "UserName")
txtUserName.Text = String.Empty
Dim txtPassword As TextBox
txtPassword = FindControlIterative(Me.cuwMain, "Password")
txtPassword.Text = String.Empty
Dim txtConfirmPassword As TextBox
txtConfirmPassword = FindControlIterative(Me.cuwMain, "ConfirmPassword")
txtConfirmPassword.Text = String.Empty
Dim txtEmail As TextBox
txtEmail = FindControlIterative(Me.cuwMain, "Email")
txtEmail.Text = String.Empty
Dim txtQuestion As TextBox
txtQuestion = FindControlIterative(Me.cuwMain, "Question")
txtQuestion.Text = String.Empty
Dim txtAnswer As TextBox
txtAnswer = FindControlIterative(Me.cuwMain, "Answer")
txtAnswer.Text = String.Empty
End Sub
It finds the textboxes correctly, but it does not actually reset their values, even though in the debugger it says it did.
Thoughts ?
What happens if you call Response.Redirect(Request.Url.ToString(), true)? That should clear everything for you.
Also, the recursive nature of the FindControlIterative call would make your code quite expensive to run as it has to drill down into the control heirarchy for every control that you are looking for.
The problem with your code is that:
In a Wizard control, ViewState is not responsible for storing the modified values for controls such as TextBoxes. These controls implement the IPostBackDataHandler interface. The LoadPostBackData event fires in the page lifecycle, in which the VALUES of the controls load from the form HTTP POST headers... which are resubmitted by the client...
So how to destroy the HTTP POST Headers to clear the control values?
A new request results in new HTTP POST Headers... simply do this in the Button click event handler:
Response.Redirect(Page.Request.Url.ToString());
This has the added benefit that it goes to Step 1 of the wizard so you also dont have to do... wiz.MoveTo(wiz.WizardSteps[0]).
Credit to Konrad - ASP.Net Wizard - How to clear contents of web controls
I feel silly posting this..., but I just turned viewstate off on the CreateUserWizard control and that did it.
Thanks for the help Daniel, I now have a better understanding on how ASP.NET stores information.

Getting information (on click) that was used to programatically generate asp controls

How may one get information that was used to programatically generate asp controls?
For example, I pulled a DataTable of user objects from the database and have organized them on a page, listing groupings such as a list of employees directly under the employer for each employer. On the page, I list each user's Username as a LinkButton. When I click one of these employees, I want to redirect the page (which is easy) and set a session variable to the selected user's UserId (which seems not so easy). How can I pull this UserId value back? These elements are not hard-coded with nice names (as they are generated in a for each loop).
Code from comment below:
Dim lnkbtnPm As New LinkButton ' is my link button. '
lnkbtnPm.Text = pmDr.Item("Username") ' where pmDr is my datarow. '
lnkbtnPm.CommandArgument = pmDr.Item("UserId")
lnkbtnPm.CommandName = "CommandNameHere"
panelToAddControlTo.Controls.Add(lnkbtnPm)
Thanks :)
I think this is what you would use the CommandName and CommandArgument properties of the LinkButton for. Assign the user id as CommandArgument and a suitable string as CommandName and hook up the Command event to an event handler:
Sub LinkButton_Command(sender As Object, e As CommandEventArgs)
' e.CommandArgument will contain the user id '
End Sub
Update
The problem is that the event handler is never attached. Use AddHandler to do that:
Dim lnkbtnPm As New LinkButton
lnkbtnPm.Text = pmDr.Item("Username") ' where pmDr is my datarow. '
lnkbtnPm.CommandArgument = pmDr.Item("UserId")
lnkbtnPm.CommandName = "CommandNameHere"
AddHandler lnkbtnPm.Command, AddressOf LinkButton_Command
panelToAddControlTo.Controls.Add(lnkbtnPm)

Resources