Changing an asp:label text inside a repeater - asp.net

I have this label inside a repeater
<asp:Label id="lblsub" runat=server text="sdds" />
I am trying to change the text of this label,this is the code behind
For Each Item As RepeaterItem In dg.Items
Dim l As New label
l = CType(Item.FindControl("lblsub"), System.Web.UI.WebControls.Label)
l.text="test"
Next
unfortunately this code doesn't work for me ,the text value doesn't change ,so I will be very happy to some help here
thanks

See my answer in this question. Believe it will solve your issue.
Getting the databound value from repeater control in asp.net
EDIT
First of all, make sure you always use quotes in your markup:
<asp:Label ID="lblsub" runat="server" Text="sdds" />
Try something like this in your code behind. Forgive me if my VB is a little rusty:
For Each Item As RepeaterItem in dg.Items
Dim l As Label = CType(Item.FindControl("lblsub"), Label)
l.Text = "test"
Next
There were just a couple little problems with syntax. I don't know if they are causing your issue, but best get the easy stuff out of the way first.

When is that bit of code being ran?
Make sure you are not rebinding the repeater afterwards by doing the following in your Page_Load:
Sub Page_load
If not Page.IsPostBack Then
BindRepeater()
End If
End Sub
If you need to do this bit of code every time the repeater is bound, then put your code into the DataBound event:
Protected Sub dg_ItemDataBound(sender As Object, e As System.Web.UI.WebControls.RepeaterItemEventArgs) Handles dg.ItemDataBound
Select Case e.item.itemtype
Case ListItemType.Item, ListItemType.AlternatingItem
Dim l As Label = e.Item.FindControl("lblsub")
l.Text = "foo"
End Select
End Sub
I haven't got any programming software with me so unsure of the syntax

C# code sample (it should be inside method or page_load)
foreach (RepeaterItem rt in MyRepeater.Items)
{
Label l = ((Label)rt.FindControl("lblPrice"));
l.Text = "200";
}

Related

visual basic asp.net dropDownList not populating with values

I have an asp.net Visual Basic web site, and I am using a stored procedure to get values to populate a drop-down list.
However, I have two issues. If I put the method to fill the drop-down list within my If Not IsPostBack statement in the page load event, then the whole list is filled with items saying 'System.Data.DataViewRow' instead of the actual values. If I put it outside this 'if' statement but still in my page load event, I get the correct values, but no matter what I select, when I leave the drop-down it reverts back to the top item instead of the selected item.
What am I doing wrong??
Edit: I have now added the DataTextField as suggested by Nic and put the method inside my 'If Not IsPostBack' event as suggested by Lee Bailey. However, my drop-down is still showing all values as 'System.Data.DataViewRow' so I don't know if Lee's solution has worked or not! Any other ideas on the issue of showing the values! I have updated my code below to reflect the changes.
The visual basic:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
bodyPanel.Visible = False
drpRegion_fill()
End If
End Sub
Protected Sub drpRegion_fill()
Dim sqlConn As SqlConnection
sqlConn = New SqlConnection
sqlConn.ConnectionString = ConfigurationManager.ConnectionStrings("ConnString").ConnectionString
Dim drpRegionCmd As SqlCommand
drpRegionCmd = New SqlCommand("getRegionName", sqlConn)
drpRegionCmd.CommandType = CommandType.StoredProcedure
Dim drpRegionAdp As SqlDataAdapter
drpRegionAdp = New SqlDataAdapter(drpRegionCmd)
Dim drpRegionDs As DataSet
drpRegionDs = New DataSet
sqlConn.Open()
drpRegionAdp.Fill(drpRegionDs)
With drpRegion
.DataSource = drpRegionDs
.DataBind()
.DataValueField = "regionName"
.DataTextField = "regionName"
.SelectedIndex = 0
End With
sqlConn.Close()
End Sub
The markup:
<asp:Panel ID="panelRegion" runat="server" Height="160px" Width="71%" CssClass="inlineBlock">
<h2>Region:</h2>
<asp:dropDownList runat="server" AutoPostBack="true" ID="drpRegion" />
</asp:Panel>
The SQL procedure returns a two-column dataset with 'regionID' as column 1, and 'regionName' as column2.
I've spent about two days on this now, trying various things and reading all the books I can! I have never had this issue in C# when I have performed the same operation and I cannot for the life of me think what I've missed in the VB...
It does not look as though you are setting the DataTextField property of your DropDownList:
With drpRegion
.DataSource = drpRegionDs
.DataValueField = "regionName"
.DataTextField = "fieldToDisplayAsText"
.SelectedIndex = 0
.DataBind()
End With
source:
MSDN DataTextField
It's reverting back to the original value because you are re-binding the values to the dropdown after a postback. Changing the selected item is triggering a postback because you have the AutoPostBack property set to true. I would call drpRegion_fill() only if it's not a postback. Setting the DataTextField as Ric mentioned should solve the problem regarding 'System.Data.DataViewRow'

Why won't FindControl find the button in the footer of my repeater?

I am using an OnItemDataBound event to attempt to activate a disabled button in a repeater. Quite simply, if the event is triggered, I know there are items in the repeater and therefore want to enable the button. Where I am getting stuck is on casting the button in the function so I can enable it. The relevant part of the repeater code is below:
<asp:Repeater ID="RptEnterHours" runat="server" DataSourceID="SQL_EmployeeGetTimesheet" ClientIDMode="Predictable" OnItemDataBound="RptEnterHours_Bound">
'.....Irrelevant code.....
<FooterTemplate>
<asp:Button Enabled="false" ID="SubmitTimesheets" Text="Submit All Timesheets" OnClick="processTimesheetEntry" runat="server" OnClientClick="checkValues();" />
</FooterTemplate>
</asp:Repeater>
This is my code behind:
Sub RptEnterHours_Bound(Sender As Object, e As RepeaterItemEventArgs)
'Exposes the Submit All Timesheets button if timesheets are available.
If (e.Item.ItemType = ListItemType.Item) Or _
(e.Item.ItemType = ListItemType.AlternatingItem) Then
Dim sButton As Button = TryCast(Me.FindControl("SubmitTimesheets"), Button)
sButton.Enabled = True
End If
End Sub
This and all other attempts has yielded the dreaded "Object reference not set to an instance of an object" message. Can anyone tell me what I am doing wrong and why my code behind won't find the button?
please try this i am sure it will help you.
If e.Item.ItemType = ListItemType.Footer Then
Dim btn as new button
btn = CType(e.Item.FindControl("SubmitTimesheets"), Button)
btn.enabled = true
End If
You're restricting it to looking within the item and alternating item templates.
Change this:
If (e.Item.ItemType = ListItemType.Item) Or _
(e.Item.ItemType = ListItemType.AlternatingItem) Then
To:
If (e.Item.ItemType = ListItemType.Footer) Then
You want to test for e.Item.ItemType = ListItemType.Footer. Item and AlternatingItem are used for the actual data records, not the footer. Therefore, the button indeed does not exist for Items and AlternatingItems.
Then, you will want to add a test for whether the RptEnterHours.DataSource object has records. For this, you will need to cast the RptEnterHours.DataSource to whatever type the data source is.
So, basically something like this. You will obviously need to change it to fit your code:
Sub RptEnterHours_Bound(Sender As Object, e As RepeaterItemEventArgs)
'Exposes the Submit All Timesheets button if timesheets are available.
If (e.Item.ItemType = ListItemType.Footer) Then
Dim sButton As Button = TryCast(Me.FindControl("SubmitTimesheets"), Button)
Dim myDataSource = CType(RptEnterHours.DataSource, MyDataSourceType)
sButton.Enabled = (myDataSource.Count > 0)
End If
End Sub
It's been a little while since I've worked with web forms, but I believe the problem is two fold.
When the item type is Item or AlternatingItem then you know you have data in the repeater. In those cases you could set an instance level flag to indicate that you have items.
Then, when the item type is footer AND you have items you want to enable to button. The way to do this is mentioned in an unaccepted answer to the question linked to by #codingkiwi.com, but I believe the problem is the context in which you're calling FindControl. You are calling Me.FindControl which will search the level 1 children of the page (or user control, or control, or whatever Me is a reference to). You want to be searching the child controls of the actual repeater element, which in this case is the footer. So the search becomes e.Item.FindControl.
It should be noted that there are probably more elegant ways to detect whether or not a repeater control has elements. Perhaps all you need to check for in the OnDataBound event is the footer item, and then look for something like: (my VB may be a bit rusty too)
If (Me.RptEnterHours.Items IsNot Null AndAlso Me.RptEnterHours.Items.Any()) Then
Not sure why its just not enabled in the first place, but this will work since it will fire for the footer after the Item/AlternatingItem types:
Private m_bolEnableButton As Boolean = False
Sub RptEnterHours_Bound(Sender As Object, e As RepeaterItemEventArgs)
'Exposes the Submit All Timesheets button if timesheets are available.
If (e.Item.ItemType = ListItemType.Item) Or _
(e.Item.ItemType = ListItemType.AlternatingItem) Then
'"if the event is triggered, I know there are items in the repeater and therefore want to enable the button"
m_bolEnableButton = True
End If
If e.Item.ItemType = ListItemType.Footer Then
If m_bolEnableButton Then
Dim sButton As Button = TryCast(e.Item.FindControl("SubmitTimesheets"), Button)
sButton.Enabled = True
End If
m_bolEnableButton = False
End If
End Sub
The reason you get the Object null reference exception is because you are fixated on the cast, which isn't causing the problem. You can generally safely cast the results of FindControl implicitly. What you need to explicitly check for is a null reference AFTER the FindControl results are captured.
Also, you should be looking for ListItemType.Footer so you can reference the footer row.
Finally, FindControl() is not recursive. It only finds controls within the top-level naming container. In most databound controls, each row represents its own naming container, so you must FindControl within the row you want to search. When you use Me, it refers to the page. You should instead use e.Item.FindControl().
Code:
Dim bRecordsFound as Boolean = False
Sub RptEnterHours_Bound(Sender As Object, e As RepeaterItemEventArgs)
If (e.Item.ItemType = ListItemType.Item) Or _
(e.Item.ItemType = ListItemType.AlternatingItem) Then
bRecordsFound = True
End If
If (e.Item.ItemType = ListItemType.Footer) And (bRecordsFound) Then
Dim sButton As Button = e.Item.FindControl("SubmitTimesheets")
If sButton IsNot Nothing Then
sButton.Visible = True
End If
End If
End Sub

Problems with repeater controls

I'm having lots of trouble understanding how repeaters are supposed to work and how I'm supposed to use them. Basically, I have a label, a set of image buttons, and a div within a repeater. When you click on the button, I want to populate the div that was created with these repeaters (so a different div for each iteration of the repeater).
It seems so simple, yet I can't get anything to work. Please help me!
Here is some of my code if that helps.
(my data source)
<asp:sqldatasource runat="server" id="dtsSpecialNotes" connectionstring="connection string" providername="System.Data.SqlClient"> /asp:sqldatasource
(my repeater)
<asp:Repeater id="rptSpecialNotes" runat="server">
<HeaderTemplate>
</HeaderTemplate>
<ItemTemplate>
</ItemTemplate>
</asp:Repeater>
(some code behind, I have a method to populate the repeater called on page load)
rptSpecialNotes.DataSource = dtsSpecialNotes
rptSpecialNotes.DataBind()
Dim imbMotion As New ImageButton
Dim imbAttachments As New ImageButton
imbMotion.ImageUrl = "images/controls/Exclaim.png"
imbMotion.Width = "40"
imbMotion.Height = "40"
imbMotion.AlternateText = "Add Motion"
imbMotion.ID = "imbMotion" & listSpecialNotesCounter
imbAttachments.ImageUrl = "images/controls/Documents.png"
imbAttachments.Width = "40"
imbAttachments.Height = "40"
imbAttachments.AlternateText = "Add Document"
imbAttachments.ID = "imbAttachments" & listSpecialNotesCounter
rptSpecialNotes.Controls.Add(lblTitle)
rptSpecialNotes.Controls.Add(imbMotion)
Here are the problems I'm having:
I can't get the repeater to iterate. It's only firing off once and then stops.
I can't get a label with the repeater data source's Subject (a field in my database) to appear.
I really appreciate any help. I just can't grasp these repeater controls.
What you want to do is populate your repeater using the ItemDataBound event as opposed to going through the item collection. That will be called for each of the items that are in the collection you assigned to the DataSource.
This is what I do when working with repeater data binding and the ItemDataBound event, I'll use a list of news items for this example:
' Bind my collection to the repeater
Private Sub LoadData()
Dim newsList As List(Of News) = dao.GetNewsList()
rptrNews.DataSource = newsList
rptrNews.DataBind()
End Sub
' Every item in the data binded list will come through here, to get the item it will be the object e.Item.DataItem
Protected Sub rptrNews_ItemDataBound(sender As Object, e As RepeaterItemEventArgs)
If e.Item.ItemType = ListItemType.Item OrElse e.Item.ItemType = ListItemType.AlternatingItem Then
' Get the current item that is being data bound
Dim news As News = DirectCast(e.Item.DataItem, News)
' Then get all the controls that are within the <ItemTemplate> or other sections and populate them with the correct data, in your case it would be an image
Dim ltlHeadline As Literal = DirectCast(e.Item.FindControl("ltlHeadline"), Literal)
Dim ltlContent As Literal = DirectCast(e.Item.FindControl("ltlContent"), Literal)
ltlHeadline.Text = news.Headline
ltlContent.Text = news.Teaser
End If
End Sub
Alternatively, you could do it all in the Markup Code and only assign the datasource and call data bind in the code behind. To achieve this you could define your ItemTemplate as follows (again with the news e.g.):
<ItemTemplate>
<tr>
<td><%#Container.DataItem("Headline")%></td>
<td><%#Container.DataItem("Teaser")%></td>
</tr>
</ItemTemplate>

ASP.NET bug in event linking of 2nd level+ dynamic controls. Test case included

The Repeater control in the following test case contains two runat="server" DIVs. Each one of them gets a TextBox appened to them through the ItemCreated event of the Repeater. Both of the have AutoPostBack=True, and TextChanged event wired to txt_TextChanged. However, only the TextBox from the first level properly points to the event on the postBack of the page. The second level TextBox also causes the postBack to occur, but its value does not persist in the VIEWSTATE as well as the event does not fire.
Here's a direct link to the test case in a .zip file (uploaded to my personal website), as well as all the code needed. The project is built in VS2010 using .NET Framework 4, but the problem also exists in 1.1, 2, and 3.5.
Anybody has any ideas on what is wrong and how to make this work?
ASPX
<asp:Repeater ID="rep" runat="server">
<ItemTemplate>
<!-- first level works -->
<div id="divOutside" runat="server">
<!-- second level doesn't work -->
<div id="divInside" runat="server"></div>
</div>
</ItemTemplate>
</asp:Repeater>
Code-Behind
Public Class WebForm1
Inherits System.Web.UI.Page
Private Sub WebForm1_Init(sender As Object, e As System.EventArgs) Handles Me.Init
If Not IsPostBack Then
Dim Table As New DataTable()
Table.Columns.Add("Column1")
Dim Row As DataRow = Table.NewRow()
Row("Column1") = ""
Table.Rows.Add(Row)
rep.DataSource = Table
rep.DataBind()
End If
End Sub
Private Sub repTest_ItemCreated(sender As Object, e As System.Web.UI.WebControls.RepeaterItemEventArgs) Handles rep.ItemCreated
' outside
Dim divOutside As HtmlGenericControl = DirectCast(e.Item.FindControl("divOutside"), HtmlGenericControl)
Dim txtInput As New TextBox
With txtInput
.ID = "txtInputOutside"
.AutoPostBack = True
.Text = "Event gets called, value persists accross postBack."
.Width = 400
End With
AddHandler txtInput.TextChanged, AddressOf txt_TextChanged
divOutside.Controls.Add(txtInput)
' inside
Dim divInside As HtmlGenericControl = DirectCast(e.Item.FindControl("divInside"), HtmlGenericControl)
txtInput = New TextBox
With txtInput
.ID = "txtInputInside"
.AutoPostBack = True
.Text = "Event NOT called, value is lost during postBack."
.Width = 400
End With
AddHandler txtInput.TextChanged, AddressOf txt_TextChanged
divInside.Controls.Add(txtInput)
End Sub
Protected Sub txt_TextChanged(sender As Object, e As EventArgs)
End Sub
End Class
Is there any reason why the textboxes have to be added to the divs dynamically? why not just put them in the aspx page with the repeater then on itemdatabound enable/disable or do whatever you need to do. That should work fine.
By the way, if you were to use panels instead of divs your on the fly approach will work.
Here's a link to Microsoft Connect, where I reported this is an official bug:
https://connect.microsoft.com/VisualStudio/feedback/details/652655/asp-net-bug-in-event-linking-of-2nd-level-dynamic-controls
It contains 2 PARTIAL workarounds that work in the uploaded files section, if anybody is interested or encounters the same problem, as well as details to what I found in the Workarounds tab.
To keep it short, it is the order of getting references to the containers and the order the TextBoxes are appended to their appropriate containers which either causes the issue or works as expected.
But, not to forget the most important point, the only reason the first-level TextBox is there in the first place is to showcase what I want as functionality. If the first-level TextBox does not get appended at all, then both workarounds fail to provide any sort of fix. Please keep that in mind when reviewing that problem - finding a workaround that revolves around changing the order of the items is not an actual solution or a fully working workaround!
Thanks everyone for the input!

Unable get Label.text in ASP.Net Repeater using FindControl

I can access the text within a textbox within my repeater, but I am unable to pull the text value from a label within my repeater.
The repeater is populated from a datatable with row(x) being filled by sqlreader(x), I don't know if that makes a difference.
I cannot use javascript for this. I need to access the label value from the codebehind.
<asp:label id="weiLabel" runat="server">
<%#DataBinder.Eval(Container, "DataItem.weiLabel")%>
</asp:label>
is the markup
I can access a textbox on the same row using:
featTable.Controls(1).Controls(1).FindControl("costText")
and retrieve the textbox.text, but using the same statement for the label gives me {text=""}.
I have verified that the clientID of control that is returned with findcontrol is correct (featTable__ctl1_weiLabel)
Thanks for any help
Can you try declaring your label like this:
<asp:label id="weiLabel" runat="server" Text='<%#DataBinder.Eval(Container, "DataItem.weiLabel")%>' / >
You can also try putting in the value into your label from the code behind using the databound method. I find it a bit easier to debug and cleaner then putting it in the html
Private Sub repPoliList_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.RepeaterItemEventArgs) Handles repPoliList.ItemDataBound
If (e.Item.ItemType = ListItemType.Item OrElse e.Item.ItemType = ListItemType.AlternatingItem) Then
Dim dr As DataRowView = CType(e.Row.DataItem, DataRowView)
Dim weiLabel As System.Web.UI.WebControls.Label= CType(e.Item.FindControl("weiLabel"), System.Web.UI.WebControls.Label)
weiLabel.text= dr("ColumnFromDatabase").toString
End If
End Sub

Resources