Gridview rowcommand event not firing in dynamically added usercontrol - asp.net

I have a usercontrol with gridview and rowcommand event.
This usercontrol is added dynamically using LoadControl on a button click of a page. The gridview's rowcommand doesn't fire.
Here is the code that loads the usercontrol on button click:
Protected Sub btnSearch_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnSearch.Click
'<ucTitle:SearchList ID="ucSearchList" runat="server" Visible="false" />
Dim ucSearchList As TitleSearchList = LoadControl("~/Controls/TitleSearchList.ascx")
ucSearchList.ISBN = txtSearchISBN.Text
ucSearchList.LoadTitleSearchList()
pnlSearchResults.Controls.Add(ucSearchList)
End Sub
And here is the code in usercontrol
Public Class TitleSearchList
Inherits System.Web.UI.UserControl
Public Property ISBN As String
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
LoadTitleSearchList()
End If
End Sub
Public Sub LoadTitleSearchList()
Dim _isbn As String = ISBN
Dim titles As New List(Of Title)
titles = New List(Of Title) From {
New Title With {.ISBN = _isbn, .TitleName = "Title check"},
New Title With {.ISBN = _isbn, .TitleName = "Title check"},
New Title With {.ISBN = _isbn, .TitleName = "Title check"},
New Title With {.ISBN = _isbn, .TitleName = "Title check"}
}
gvTitle.DataSource = titles
gvTitle.DataBind()
End Sub
Public Sub gvTitle_Rowcommand(ByVal sender As Object, ByVal e As GridViewCommandEventArgs) Handles gvTitle.RowCommand
If e.CommandName = "TitleDetail" Then
Response.Redirect("TitleSearch.aspx?isbn=" & e.CommandArgument().ToString())
End If
End Sub
End Class

Events in GridViews that are added dynamically in a UserControl get a little ugly. Since UserControls that are added dynamically have to be re-added on the post-back, you have to rebind the GridView DataSource, which makes you lose out on automatically getting those Events fired for you. That being said, you can still pull it off with some parsing of the __EVENTTARGET of the Form.
Add a HiddenField that tells you whether or not you need to re-add the UserControl. Add this in your Page_Load Event Handler:
If CBool(hdnTitleSearchActive.Value) = True Then
AddSearchListToPanel()
End If
Call AddSearchListToPanel() in your btnSearch_Click Event Handler.
Now this implementation of AddSearchListToPanel can be cleaned up some, but this should be good enough to get you going. Note that the Button triggering the GridView Command in my example has the ID of lbtTest. You will have to adjust based on the ID that you are using.
Private Sub AddSearchListToPanel()
Dim ucSearchList As TitleSearchList = LoadControl("~/Controls/TitleSearchList.ascx")
ucSearchList.ISBN = txtSearchISBN.Text
ucSearchList.LoadTitleSearchList()
pnlSearchResults.Controls.Add(ucSearchList)
hdnTitleSearchActive.Value = True
Dim strEventTarget As String = HttpContext.Current.Request.Form("__EVENTTARGET")
If Not strEventTarget Is Nothing AndAlso strEventTarget.Contains("gvTitle$") AndAlso _
strEventTarget.Contains("$lbtTest") Then
'Value example = gvTitle$ctl02$lbtTest
Dim intRowNumber As Integer = (CInt(strEventTarget.Substring(11, 2)) - 1)
Dim lbtCommandSource As LinkButton = CType(CType(ucSearchList.FindControl("gvTitle"), GridView).Rows(intRowNumber).FindControl("lbtTest"), LinkButton)
Dim objCommandEventArguments As New CommandEventArgs(lbtCommandSource.CommandName, lbtCommandSource.CommandArgument)
Dim objGridViewCommandEventArgs As New GridViewCommandEventArgs(lbtCommandSource, objCommandEventArguments)
ucSearchList.gvTitle_Rowcommand(lbtCommandSource, objGridViewCommandEventArgs)
End If
End Sub

Related

Visual Studio Have to Click Button Twice

I'm trying to write code that will, at the click of a button, push a string variable onto a page and then open that page. The trouble that I am running into is that variable, a button's text, is nested within a gridview, making accessing it difficult. It is also difficult because I am importing it from an SQL database into the Gridview, so I cannot access it directly from there either. It works with my current code if I use the button's onClick event, but then for some reason I have to click the button twice in order for it to work. I have read on here to instead use the onPreRender event, but that interferes with pushing the string variable onto the page, and I can't have that. Is there any other way to get rid of having to click the button twice that doesn't involve the onPreRender event?
Here is the code:
Imports System.Data.SqlClient
Imports System.IO
Partial Class PartsLookup
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
End Sub
Private Function FindControlRecursive(ByVal RootControl As Control, ByVal ControlID As String) As Control
If RootControl.ID = ControlID Then
Return RootControl
End If
For Each controlToSearch As Control In RootControl.Controls
Dim controlToReturn As Control = FindControlRecursive(controlToSearch, ControlID)
If controlToReturn IsNot Nothing Then
Return controlToReturn
End If
Next
Return Nothing
End Function
Protected Sub Button1Click(ByVal sender As Object, ByVal e As System.EventArgs)
Dim clickedButton As Button = sender
MsgBox(clickedButton.Text)
Dim ControlText As Control = FindControlRecursive(GridView1, clickedButton.ID)
Dim ControlText1 As Button = ControlText
Dim MachineNumber As String = ControlText1.Text
If MachineNumber = "" Then
ControlText1.Visible = False
End If
Dim SpecificPart() As String = {String that is the files contents, the middle of which is where the variable will be pushed to}
Dim path As String = "File path where the variable is to be pushed to"
File.WriteAllLines(path, SpecificPart)
clickedButton.PostBackUrl = "~/PartNumberPages/PartTemplate.aspx"
End Sub
End Class

Failure to update textbox.text

I have a relatively simple ASP.NET problem (I should think) that regrettably I am unable to solve by myself. What I am trying to do is the following:
On a page I load a number of controls (Text Boxes) programmatically;
following this load the user should be able to select a value to load into the Textbox from a panel control that is added to the page following the click of a button
Once the panel is closed, the selected text from the panel should be loaded into the textbox
However, in the vb.net statements below when run the "test" string never makes it to the textbox - any help with resolving this would be greatly appreciated.
Public Class test
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Controls_Load()
End Sub
Public Sub Controls_Load()
Dim ttf_tb As New TextBox With {.ID = "ttf_tb"}
Master_Panel.Controls.Add(ttf_tb)
Dim ttf_button As New Button
Master_Panel.Controls.Add(ttf_button)
AddHandler ttf_button.Click, AddressOf TTF_BUTTON_CLICK
End Sub
Public Sub TTF_BUTTON_CLICK(sender As Object, e As EventArgs)
Dim str As String = sender.id
Dim panel As New Panel
panel.ID = "TTF_Panel"
panel.Width = 300
panel.Height = 300
Master_Panel.Controls.Add(panel)
panel.BackColor = Drawing.Color.Black
panel.Style.Add(HtmlTextWriterStyle.Position, "absolute")
panel.Style.Add(HtmlTextWriterStyle.Left, "200px")
panel.Style.Add(HtmlTextWriterStyle.Top, "100px")
panel.Style.Add(HtmlTextWriterStyle.ZIndex, "100")
Dim CL_Button As New Button
CL_Button.ID = "TTF_Close_" & Replace(str, "TTF_Button_", "")
panel.Controls.Add(CL_Button)
AddHandler CL_Button.Click, AddressOf TTF_Close_Button_Click
End Sub
Public Sub TTF_Close_Button_Click(sender As Object, e As EventArgs)
Dim ttf_tb As TextBox = Master_Panel.FindControl("ttf_tb")
ttf_tb.Text = "Test"
Dim panel As Panel = FindControl("TTF_Panel")
Master_Panel.Controls.Remove(panel)
End Sub
End Class
I think you need to re-create your controls in the Page_Init method. It's been a while since I've done web forms but I think it's something like:
When a user clicks the button a post back is fired. This re-creates a new instance of your class, creates the controls on the page, assigns any form values then calls your Page_Load event.
The problem is you are creating your controls too late, so the forms values are never assigned correctly.
You should create / recreate your dynamic controls in the Init event:
Protected Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Init
Controls_Load()
End Sub
This should allow you to maintain their state across PostBacks.
For more information about this topic, see the MSDN article on the ASP.NET Page Life Cycle.

Asp.Net Null Reference Exception on Event Handler for Dynamic Controls

I've created some dynamic controls on page load and added an event handler to handle the click event of a dynamic link button. Within the sub of the click event handler, I need to reference some other (non-dynamic) controls on the page and change their value. However, I get a null reference exception - object not set to an instance of an object - each time I try to reference a control on the page (in this case label1). What am I doing wrong in creating these dynamic controls or with my event handler? Thanks!
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
'Get the data to populate the controls
Dim oMySqlData As New MySqlDataProvider
PlaceHolder1.Controls.Add(CreateExistingNotesHTML(oMySqlData.GetParentNotes("104628"), oMySqlData.GetChildNotes("104628")))
End Sub
Public Sub OnCommentClick(ByVal sender As Object, ByVal e As EventArgs)
'The event handler for the link buttons
Label1.Text = "You clicked " & DirectCast(sender, LinkButton).ID
End Sub
Public Function CreateExistingNotesHTML(ByVal dtParent As DataTable, ByVal dtChild As DataTable) As HtmlGenericControl
'The routine that creates the dynamic controls
Dim divContainer As New HtmlGenericControl("div")
For Each drParent As DataRow In dtParent.Rows()
divContainer.Controls.Add(WriteNote(drParent.Item("NoteId").ToString(), drParent.Item("UserName").ToString(), drParent.Item("ItemNote").ToString, CDate(drParent.Item("InsertDate")), "note"))
Next
Return divContainer
End Function
Private Function WriteNote(ByVal NoteId As String, ByVal UserName As String, ByVal ItemNote As String, ByVal InsertDate As DateTime, ByVal DivClass As String) As HtmlGenericControl
Dim div As New HtmlGenericControl("div")
div.ID = "d" & NoteId
div.Attributes.Add("class", DivClass)
div.Controls.Add(New LiteralControl(" ยท "))
'Add the dynamic link buttons
Dim lnkComment As New LinkButton
lnkComment.ID = "l" & NoteId
lnkComment.Text = "Comment"
lnkComment.Style("Text-decoration") = "none"
AddHandler lnkComment.Click, AddressOf oNotes.OnCommentClick
div.Controls.Add(lnkComment)
Return div
End Function
With this line
Dim oNotes As New EbayItemNotes
AddHandler lnkComment.Click, AddressOf oNotes.OnCommentClick
You are handling this event outside of your page and within the EbayItemNotes class, how does this class know anything of Label1 that resides in your page?
Could it be that you need to pass your label in as well..
Dim oNotes As EbayItemNotes = new EbayItemNotes(label1)
inside EbayItemNotes constructor
public sub New(lbl as Label) //store this label for use in event handler..

re-add your handler on every postback

when the page is loaded the following code is invoke
page load
Dim products As New LinkButton
products.Text = "Products"
testPanel.Controls.Add(products)
AddHandler products.Click, AddressOf getProducts
getProducts function
Dim testDb As New Product
Dim arr As ArrayList = testDb.DbLoop()
Dim ObjList As ProductBo
Dim ID As Integer
Dim link As LinkButton
For Each ObjtList In arr
ID= ObjtList.C_Id
link = New LinkButton
testPanel.Controls.Add(New LiteralControl("<br />"))
link.ID = ID
link.Text = ObjList.Name
link.CommandArgument = CustInt
Me.testPanel.Controls.Add(link)
AddHandler link.Click, AddressOf getProductsDetails
Next ObjList
what i want to achive when the page load i link is create Products when i click on products link it invoke an event handler call getProducts. getproducts will loop in the database to fetch all record then it will creat a link for each product name when i click on the product name it should invoke another event. my problem is how can i re add control after every postback thank u
Because the links are dynamically created, you have to re-create and re-add the handler for them on each postback.
On the _init event, you have to check the state you are in (before product load or after product load), then create either the Product Load link OR the Product Details link. Key is they have to be created EVERY postback AND they have to be created before the _Load event. Typically this should be done on the _Init event.
Something along the lines of this:
Private Sub Page_Init(sender As Object, e As System.EventArgs) Handles Me.Init
If ViewState.Item("ProductsLoaded") IsNot Nothing Then
If ViewState.Item("ProductsLoaded").ToString = "True" Then
GetProducts(Me, New EventArgs)
Else
CreateProductsButton()
End If
Else
CreateProductsButton()
End If
End Sub
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
End Sub
Private Sub CreateProductsButton()
Dim btnProducts As New LinkButton
btnProducts.Text = "Products"
testPanel.Controls.Add(btnProducts)
AddHandler btnProducts.Click, AddressOf GetProducts
ViewState.Item("ProductsLoaded") = False.ToString
End Sub
Private Sub GetProducts(sender As Object, e As EventArgs)
' get products list here
' and set handlers for each link
ViewState.Item("ProductsLoaded") = True.ToString
End Sub
Private Sub GetProductsDetails(sender As Object, e As EventArgs)
'get product details here
End Sub

ITemplate and linkbutton click event

In my user control I have gridview, and this grid is created programmatically, using Itemplate. In InstantiateIn methods I have this code.
Select Case _templateType
Case ListItemType.Header
Dim linkButton As New LinkButton
linkButton.Text = "Delete"
linkButton.CommandName = "Click"
linkButton.CommandArgument = Me._columnID
container.Controls.Add(linkButton)
I want to wired up Click event to this LinkButton, and use this event in code behind.
This is constructor of GridViewTemplate how implements ITemplate
Public Sub New(ByVal type As ListItemType, ByVal colname As String, Optional ByVal infoType As String = "")
'Stores the template type.
_templateType = type
'Stores the column name.
_columnName = colname
_infoType = infoType
_columnID = columID
End Sub
and i have this call from user control:
bfield.ItemTemplate = New GridViewTemplate(ListItemType.Item, dt.Columns(col).ColumnName, "label")
where is
Dim bfield As TemplateField = New TemplateField()
AddHandler linkbutton.Click, AddressOf X 'X being the method that handles the click event.
AddHandler linkButton.Click, AddressOf linkButton_Click
Sub linkButton_Click(ByVal sender As System.Object, ByVal e As EventArgs)
' here is your click handler
End Sub

Resources