I have a form which contains a repeater with a HiddenField control within whose IDs are dynamically created.
Dim tNewOrder As HiddenField = CType(e.Item.FindControl("tNewOrder"), HiddenField)
tNewOrder.ID = "tNewOrder" & CategoryId
When I submit the form i'm looping through the repeater and trying to access each HiddenField value but i get error 'Object reference not set to an instance of an object.'
For Each CatItem As RepeaterItem In reCategory.Items
Dim hCategoryId As HiddenField = CType(CatItem.FindControl("hCategoryId"), HiddenField)
Dim tNewOrder As HiddenField = CType(CatItem.FindControl("tNewOrder" & hCategoryId.Value), HiddenField)
Response.Write(tNewOrder.Value)
Next
Is there a way to find controls with dynamically generated IDs?
I've found a way around the issue so thought i'd post it here.
Instead of dynamically creating the control IDs I set ID to 'tNewOrder' and the ClientIDMode:
change this line:
tNewOrder.ID = "tNewOrder" & CategoryId
to:
tNewOrder.ClientIDMode = UI.ClientIDMode.Predictable
I then knew the IDs would be generated as tNewOrder_0, tNewOrder_1, tNewOrder_2 per repeater index.
So I could then access the values by:
For Each CatItem As RepeaterItem In reCategory.Items
Dim tNewOrder As HiddenField = CType(CatItem.FindControl("tNewOrder"), HiddenField)
Response.Write(tNewOrder.Value)
Next
Related
Suppose I have a gridview containing some bound fields and a template field. The template field contains a button (btnUpload).
btnUpload triggers a modalpopupextender to display a panel which contains some controls and a submit button.
What I need to be able to do is to get the value from cell 0 of the row btnUpload was clicked on and pass it to the panel so I can retrieve some data into the panel's controls in the panel_load event based on that value from cell 0 of the gridview.
I thought I could do this by storing the value from cell 0 in a session variable but not sure if this is the 'best' way of doing this?
UPDATE - Using hidden fields on the panel to store row index as suggested by Karl
I have added two hidden fields to the panel and I populate them as below:
If e.CommandName = "Upload" Then
Dim row As GridViewRow = CType(CType(e.CommandSource, Control).NamingContainer, GridViewRow)
Dim ref As String = CType(row.Cells(0), DataControlFieldCell).Text
Dim dt As String = CType(row.Cells(2), DataControlFieldCell).Text
hfRef.Value = ref
hfDate.Value = dt
End If
This is working and populating the hidden fields OK. However in the btnSubmit_Click event procedure on the panel I am doing the following the variables I am assigning are not getting a value from the hidden fields:
If fuCertificate.HasFile Then
Dim fileName As String = Path.GetFileName(fuCertificate.PostedFile.FileName)
fuCertificate.SaveAs(Server.MapPath("~/CalibrationCerts/" & fileName))
Dim ref As String = hfRef.Value
Dim dt As String = hfDate.Value
Dim dc As New ExternalCalibrationDataContext
Dim thisRecord = (From x In dc.ext_calibration_records
Where x.calibration_no = ref AndAlso
x.calibration_date = dt).ToList()(0)
thisRecord.certificate_no = txtCertNumber.Text
thisRecord.certificate = "~/CalibrationCerts/" & fileName
Else
lblError.Text = "Please select a file to upload"
End If
I would recommend putting a HiddenField control in the panel used by the ModalPopupExtender. It will be easier to work with the HiddenField control than Session, because you will not need to do the casting of the hidden field Value to a string, because it already is a string. All Session objects are stored as Object, so it is necessary to cast to a string when retrieving the value from Session.
Hidden field option:
<asp:Panel>
// Other stuff for your modal popup
<asp:HiddenField id="HiddenField1` runat="server" />
</asp:Panel>
// Set hidden field
HiddenField1.Value = cell0.Text
// Get hidden field
string theValue = HiddenField1.Value
Session option:
// Set the value in Session
Session["Cell0Text"] = cell0.Text
// Retrieve the value from Session
// First check to see if the Session value still exists
if(Session["Cell0Text"] != null)
{
// Now cast the Session object to a string
string theValue = Session["Cell0Text"].ToString()
}
I'm using a custom template class to generate lines with my repeater control, i'd like to be able to specify the controls in this repeater dynamically from the code behind my aspx page.
In the code behind I've added controls to a list like this:
Dim lstControls As New List(Of Control)
lstControls.Add(New TextBox)
lstControls.Add(New Label)
lstControls.Add(New CheckBox)
lstControls.Add(New DropDownList)
lstControls.Add(New CheckBox)
Then i use this line to add the controls to my template
rptrSummary.ItemTemplate = New myTemplate(ListItemType.Item, , lstControls)
From the instantiateIn sub i'm doing something like this:
Dim ph As New PlaceHolder
For i = 0 To lstControls.Count - 1
ph.Controls.Add(lstControls(i))
Next
This doesn't work properly and following .databind() of my repeater control the controls i specify only appear on the final row. I think this is because i've only declared the controls as NEW once, so i only have one rows worth.
tldr?/ conclusion:
How can i generate new controls of the same type as controls from my list? Something like:
Dim newControl as new Control = type(lstControl(0))
(this obviously doesn't work)
I've found the answer, here are some examples in case anyone else is stuck (i may also change the title so it's more similar to likely search criteria):
dim egTextbox as new textbox
dim egLabel as new label
dim newObject1 as Object = Activator.CreateInstance(egTextbox.GetType)
dim newObject2 as Object = Activator.CreateInstance(egLabel.GetType)
newObject1 is now a textbox
newObject2 is now a label
I created an ASP Table Control and added a row to it programatically. I then repeated the process to add another row. The first row that I added disappeared and only the newest row is being displayed. Is there a property that needs to be set to allow the state of the table to be saved?
EDIT:
All I do is click a button on the page and it adds a row to the table. Repeated clicks of the button only add one from to the table. If it helps, here is the function that adds the rows.
Protected Sub addItemButton(sender As Object, e As EventArgs)
'get the id of the item they selected
Dim id As String = CType(sender, Button).Text
'clear out the data being displayed
gridViewItemSearchItems.DataSource = Nothing
gridViewItemSearchItems.DataBind()
'add this item to the line table
Dim itemToAdd As Item = gp.Items.GetItemByKey(id)
Dim tableRow As New System.Web.UI.WebControls.TableRow()
Dim cellId As New System.Web.UI.WebControls.TableCell
cellId.Text = itemToAdd.Key.Id
Dim cellDesc As New System.Web.UI.WebControls.TableCell
cellDesc.Text = itemToAdd.Description
Dim cellMSRP As New System.Web.UI.WebControls.TableCell
cellMSRP.Text = gp.Items.GetItemMSRP(itemToAdd.Key)
Dim cellCost As New System.Web.UI.WebControls.TableCell
cellCost.Text = itemToAdd.CurrentCost.Value
Dim cellUnitPrice As New System.Web.UI.WebControls.TableCell
cellUnitPrice.Text = itemToAdd.StandardCost.Value
Dim cellDiscount As New System.Web.UI.WebControls.TableCell
cellDiscount.Text = "12%"
Dim cellQuantity As New System.Web.UI.WebControls.TableCell
cellQuantity.Text = "1"
tableRow.Cells.Add(cellId)
tableRow.Cells.Add(cellDesc)
tableRow.Cells.Add(cellMSRP)
tableRow.Cells.Add(cellCost)
tableRow.Cells.Add(cellUnitPrice)
tableRow.Cells.Add(cellDiscount)
tableRow.Cells.Add(cellQuantity)
tblItems.Rows.Add(tableRow)
End Sub
Since you're adding the rows to your table dynamically, they have to be re-created on each successive post-back.
Look at this answer for an explanation as to why dynamically added controls can disappear: ASP.NET dynamically created controls and Postback
EDIT: It is possible to dynamically add controls during a post-back, my answer here shows a way to do that using ViewState. Although, this does become very cumbersome. You might want to re-think the design of the page.
On my webpage I am loading multiple instances of a usercontrol, sometimes the usercontrol is laoded within itself. I need to save a bunch of properties for the round trip of a post back but i am confused on how to save those properties to ViewState and set them again to the repeater items within the usercontrol.
Can anyone help me in this situation, I have read the MSDN on Viewstate but I am not understanding it quite well for some reason
This is how I load the parent user controls (child controls are loaded the same way with the same user control)
Protected Sub Load_Controls(ByVal list As List(Of BSEvaluationGroup.category), ByVal gid As Integer, ByVal pid As Integer, ByVal fid As Integer)
Dim item As BSEvaluationGroup.category
For Each item In list
Dim ctl As PerformanceEvaluationSubcontractorControl = CType(Page.LoadControl("PerformanceEvaluationSubcontractorControl.ascx"), PerformanceEvaluationSubcontractorControl)
ctl.categoryid = item.catid
ctl.categoryname = item.catname
ctl.projectid = pid
ctl.folderid = fid
ctl.groupid = gid
ctl.parentid = item.parid
ctl.clist = item.categories
ctl.plist = item.points
ctl.parentpage = Me
ctl.EnableViewState = "true"
If (Not subcon Is Nothing AndAlso Not subcon.points Is Nothing) Then
ctl.epnts = subcon.points
End If
AddHandler ctl.BubbleCalculate, AddressOf Me.PostRating
Select Case gid
Case 1
Me.officephld.Controls.Add(ctl)
Dim ohrule As HtmlGenericControl = New HtmlGenericControl("hr")
ohrule.Style.Add("width", "100%")
ohrule.Style.Add("background-color", "Silver")
ohrule.Style.Add("size", "1px")
ohrule.Style.Add("border-width", "0")
ohrule.Style.Add("padding-top", "1px")
ohrule.Style.Add("float", "left")
Me.officephld.Controls.Add(ohrule)
Case 2
Me.sitephld.Controls.Add(ctl)
Dim shrule As HtmlGenericControl = New HtmlGenericControl("hr")
shrule.Style.Add("width", "100%")
shrule.Style.Add("background-color", "Silver")
shrule.Style.Add("size", "1px")
shrule.Style.Add("border-width", "0")
shrule.Style.Add("padding-top", "1px")
shrule.Style.Add("float", "left")
Me.sitephld.Controls.Add(shrule)
End Select
Next
End Sub
Accessing view-state is simple such as ViewState("PropertyName"). The View State bag is specific to a control instance so you can use same property name within multiple control types and instances.
Only important thing here is that ASp.NET run-time has to match view-state bags to control instances and for that it uses ID property (which is unique within the parent naming container). So its important that you assign unique IDs to your dynamic user control instances ( and maintain same control tree hierarchy and ids on postback - essentially it means that execute the same code on postback and don't use random ids). So your code should be something like
...
Dim n As Integer
n = 1
For Each item In list
Dim ctl As PerformanceEvaluationSubcontractorControl = CType(Page.LoadControl("PerformanceEvaluationSubcontractorControl.ascx"), PerformanceEvaluationSubcontractorControl)
ctl.ID = "MyCtl" & n.ToString()
ctl.categoryid = item.catid
....
It was a control ID issue, I removed it instead of adding an ID
I have a drop down menu, and based on which item is selected, I call a web service and then dynamically create some text boxes.
The first time I drop down the menu and select an item, it works perfectly, and the text boxes are created and populated dynamically. However, the next time I drop down the menu (after the first postback), and select something different... after the second postback, the original values remain in the textboxes.
I am clearing all of the text boxes out of the placeholder, then re-creating them, and then setting a NEW value, how can they retain the OLD values... especially if I controls.clear them from the page?
Note: The second time they are being created, the textbox IDs DO end up being the same. Could that have something to do with it? This duplicate ID functionality will need to be supported.
My code, called from Page_Load, is as follows: (edited to add more code)
Private Sub RefreshEntity()
Dim XmlRecords As New XmlDocument
Dim XmlRecordsNode As XmlNode
Dim EntityType As String = EntityTypes.SelectedValue
Dim Entity As String = RecordValue.Value
Dim FieldName As String
Dim FieldValue As String
FieldPlaceHolder.Controls.Clear()
If RecordList.SelectedValue <> "Select..." Then
Try
XmlRecordsNode = LoginInfo.SharePointConnectWebService.GetMetaData(LoginInfo.WSUser, LoginInfo.WSPass, _
EntityType, Entity)
XmlRecords.LoadXml(XmlRecordsNode.OuterXml)
Catch ex As Exception
ConfirmLabel.Text = "<b>Error:</b><br>" & ex.Message.ToString
Return
End Try
Else
SetProperties.Visible = False
Return
End If
For Each OneNode As XmlNode In XmlRecords.SelectNodes("Fields").Item(0).ChildNodes
FieldName = OneNode.Name
FieldValue = OneNode.InnerText
Dim newLabel As Label = New Label()
newLabel.Text = FieldName & ": "
Dim newTextBox As TextBox = New TextBox()
newTextBox.ID = "Field-" & FieldName
newTextBox.Text = FieldValue
Dim newLine As Label = New Label()
newLine.Text = "<br><br>"
FieldPlaceHolder.Controls.Add(newLabel)
FieldPlaceHolder.Controls.Add(newTextBox)
FieldPlaceHolder.Controls.Add(newLine)
Next
SetProperties.Visible = True
End Sub
And the RecordValue.Value is a hidden field that gets populated in every Page_Load:
RecordValue.Value = RecordList.SelectedValue
Where RecordList is my DropDown menu.
This is likely due to ViewState or the Posted values clobbering your values.
Once a control is dynamically added to the controls collection it needs to catch up with all the page life cycle events that have already fired. In the case of a post back this means that the ViewState and/or the posted form value will clobber the .text property on the TextBox based on the order you're adding the dynamic controls to the controls collection and setting the .text property.
To fix this you can disable ViewState by setting the .EnableViewState property to false on the dynamically generate controls also add the controls to the controls collection before you set any properties on them.
For Each OneNode As XmlNode In XmlRecords.SelectNodes("Fields").Item(0).ChildNodes
FieldName = OneNode.Name
FieldValue = OneNode.InnerText
Dim newLabel As Label = New Label()
Dim newTextBox As TextBox = New TextBox()
Dim newLine As Label = New Label()
newTextBox.ID = "Field-" & FieldName
newLabel.EnableViewState = False
newTextBox.EnableViewState = False
newLine.EnableViewState = False
FieldPlaceHolder.Controls.Add(newLabel)
FieldPlaceHolder.Controls.Add(newTextBox)
FieldPlaceHolder.Controls.Add(newLine)
newLabel.Text = FieldName & ": "
newTextBox.Text = FieldValue
newLine.Text = "<br><br>"
Next
You're not storing the value in a Session variable and then putting it back into the text box later in your code?